C++一些注意点之继承和派生 (一)

2014-11-24 00:59:33 · 作者: · 浏览: 6

1.继承权限:

public:公有派生,基类中所有成员在公有派生类中保持各个成员的访问权限。基类public成员,在派生类也为public成员;基类protected成员,在派生类可以访问,在派生类之外不能直接访问;基类private成员,除了基类的成员函数能访问之外,其他都不能访问。基类对基类对象和派生类对象的访问权限时一样的。

protected:与私有继承的情况相同。两者的区别在于基类成员对其对象的可见性与一般类及其对象可见性相同。公有成员可见,其他成员不可见。基类的公有成员和保护成员都作为派生类的保护成员,并且不能被这个派生类的子类所访问。基类对派生类对象所有成员都不可见。保护继承无法再往下继承。

private: 私有派生,基类中公有成员和保护成员在派生类中均变为私有的,在派生类中仍然可以直接访问这些成员,但是在派生类之外均不可直接使用基类的公有或私有成员。基类对基类对象保持原有权限,基类对派生类对派生类对象来说所有都是私有成员。私有继承无法再往下继承。

2.抽象类:定义一个类,只用作基类派生新类,而不能用作定义对象,该类称为抽象类。

当把一个类的构造函数或析构函数的访问权限定义为保护时,这种类称为抽象类。因为在定义对象的时候要调用构造函数和析构函数,所以构造函数或者析构函数定义为保护的权限时都行。但是派生类在构造时要调用基类的构造函数和析构函数,所以也不能将构造函数或者析构函数声明为私有的。

另一种定义:当类中含有纯虚函数时,为抽象类。

3.初始化基类成员:派生类一方面要调用派生类的构造函数来初始化在派生类新增的成员,另一方面要调用基类的构造函数来初始化派生类中的基类成员。调用顺序是这样的:

(1)调用基类的构造函数;(调用顺序取决于继承的一个顺序)

(2)调用对象成员的构造函数;(调用顺序取决于在类对象在派生类中的声明顺序)

(3)调用自己的构造函数。(初始化成员时,跟变量的定义顺序有关)

例子:


[html]
#include


using namespace std;


class Base1{
int x;
public:
Base1(int a)
{
x = a;
cout<<"调用基类1的构造函数"< }
~Base1()
{cout<<"调用基类1的析构函数"< };


class Base2{
int y;
public:
Base2(int b)
{
y = b;
cout<<"调用基类2的构造函数"< }
~Base2()
{cout<<"调用基类2的析构函数"< };


class Der:public Base1,public Base2{
private:
int z;
Base1 b1,b2;
public:
Der(int a,int b):Base2(a),b1(200),b2(a+b),Base1(20)
{
z = b;
cout<<"调用派生类的构造函数"< }
~Der()
{cout<<"调用派生类的析构函数"< };




int main()
{
if(1){
Der d(100,200);
}
system("pause");
return 0;
}

#include


using namespace std;


class Base1{
int x;
public:
Base1(int a)
{
x = a;
cout<<"调用基类1的构造函数"< }
~Base1()
{cout<<"调用基类1的析构函数"< };


class Base2{
int y;
public:
Base2(int b)
{
y = b;
cout<<"调用基类2的构造函数"< }
~Base2()
{cout<<"调用基类2的析构函数"< };


class Der:public Base1,public Base2{
private:
int z;
Base1 b1,b2;
public:
Der(int a,int b):Base2(a),b1(200),b2(a+b),Base1(20)
{
z = b;
cout<<"调用派生类的构造函数"< }
~Der()
{cout<<"调用派生类的析构函数"< };


int main()
{
if(1){
Der d(100,200);
}
system("pause");
return 0;
}

运行结果:

3.冲突与支配原则和赋值兼容性

(1)冲突

一个派生类从多个基类派生而来,当基类中成员的访问权限设为public,且不同的基类成员就有相同的名字时,就会出现冲突。(这个一定同时继承的两个基类中有相同的名字才会冲突,派生类和基类有相同的名字不会冲突)例如:


[html]
#include

using namespace std;

class Base1{
int x;
public:
Base1(int a)
{x = a;}
void show(){cout<<"x="< };

class Base2{
int x;
public:
Base2(int b)
{x = b;}
void show(){cout<<"x="< };

class Der:public Base1,public Base2{
private:
int z;
public:
void setx(int a){x=a;} //D
};


int main()
{
Der d;
d.show(); //E
return 0;
}

#include

using namespace std;

class Base1{
int x;
public:
Base1(int a)
{x = a;}
void show(){cout<<"x="< };

class Base2{
int x;
public:
Base2(int b)
{x = b;}
void show(){cout<<"x="< };

class Der:public Base1,public Base2{
private:
int z;
public:
void setx(int a){x=a;} //D
};


int main()
{
Der d;
d.show(); //E
return 0;
}
这时,D行访问基类中的成员,这是编译器无法确定是要访问属于哪一个类的x,即出现编译错误;同样的x也会错误,编译器不知道调用哪个基类的show函数。

解决这种冲突办法:使各基类中的成员不同;各基类将成员设为私有的,并设置相应的访问函数,访问函数不能重名;使用作用域来说明。


[html]
#include

using namespace std;

class Base1{
int x;
public:
Base1(int a)
{x = a;}
void show(){cout<<"x="< };

class Base2{
int x;
public:
Base2(int b)
{x = b;}
void show(){cout<<"x="< };

class Der:public Base1,public Base2{
private:
int z;
public:
void setAx(int a){Base1:x=a;} //D
void setBx(int a){Base2: