面向对象程序设计的核心:对象、类和继承,如果再加一种的话应该是多态性; //来自C++ Program Design [美] James P.Cohoon & Jack W.Davidson C++程序设计(第三版)中文译本 P649
1、派生类格式
class 派生类类:[访问属性,public、protected、private,默认值]基类名
{
... ...
};
class CXABC
{
private:
int a;
protected:
int b;
public:
int c;
public:
CXABC();
virtual ~CXABC();
static int x;
};
class CXABC2 : public CXABC
{
public:
void Test();
CXABC2();
virtual ~CXABC2();
};
1.1、public类型继承属性
保持基类中各成员属性不变,也即从基类继承过来的派生类成员具有与基类对成员的相同的保护机制,另外基类中private成员变为不可访问。派生类的成员只能访问基类中的public/protected成员,而不能访问private成员;派生类的对象只能访问基类中的public成员。
派生类的成员函数或派生类的对象调用时,VC6编译时均给以下出错提示:error C2248: 'a' : cannot access private member declared in class 'CXABC' error C2248: 'b' : cannot access protected member declared in class 'CXABC'
例题:基类中的protected成员,通过public继承,基在派生类的可见性为:A、不可访问 B、private C、protected D、public
1.2、protected类型访问属性
基类中各成员属性均变为protected,并且基类中private成员被隐藏。派生类的成员只能访问基类中的public/protected成员,而不能访问private成员;派生类的对象不能访问基类中的任何的成员。
1.3、private类型访问属性
基类中各成员属性均变为private,并且基类中private成员被隐藏。派生类的成员同样只能访问基类中的public/protected成员,而不能访问private成员;派生类的对象不能访问基类中的任何的成员。
在《c++primer第四版中文》中p579,对“派生类到基类转换的可访问性”讲的比较模糊,于是用visual studio 2008花了四个小时把大部分能想到的情况都试验了一下,得出如下结果。
这里的后代类指的是由基类派生的派生类派生出来的类。也就是类层次中的第三层。
当为public派生时:
派生类定义体中:
构造函数中:
构造函数体中不能定义派生类对象(虽然能通过编译,但运行中会出现错误),但可以定义基类对象、指针和引用。
可以定义派生类和基类的指针及引用。既然不能定义派生类对象,就无法初始化引用(引用必须在定义时初始化),也就无法让派生类的引用对基类引用初始化或赋值了。并且,派生类的指针也不能初始化,只能赋空值,这样派生类的指针就可以对基类指针初始化或赋值。但这么做似乎没有什么意义。
复制控制成员:
复制函数:
可以定义派生类和基类的对象、指针、引用。
除了派生类复制函数的功能不能使用外(即不能用派生类对象对派生类对象进行初始化),其它和用户代码中一样。
赋值函数:
可以定义派生类和基类的对象、指针、引用。
除了派生类赋值函数的功能不能使用外(即不能用派生类对象对派生类对象进行赋值),其它和用户代码中一样。
析构函数:
构造函数体中不能定义派生类对象(虽然能通过编译,但运行中会出现错误),但可以定义基类对象。
其它函数体中:
可以定义派生类和基类的对象、指针、引用。
情况和在派生类用户代码中一样。
其它位置:
只能定义派生类指针,能定义基类对象、指针和引用。
后代类定义体中:
所有成员函数中:
可以定义派生类和基类的对象、指针、引用。
情况和在派生类用户代码中一样。
其它位置:
可以定义派生类和基类的对象、指针、引用。
后代类的用户代码:
后代类对象可以对基类对象进行初始化和赋值;
后代类对象的地址可以对基类的指针进行初始化和赋值;
后代类的对象和引用可以对基类的引用进行初始化和赋值;
派生类用户代码中:
派生类对象可以对基类对象进行初始化和赋值;
派生类对象的地址可以对基类的指针进行初始化和赋值;
派生类的对象和引用可以对基类的引用进行初始化和赋值;
当为protected派生时:
派生类定义体中:
由于派生列表中的访问标号只对用户代码和后代派生类有影响,对派生类访问基类成员没有影响,所以,此处情况应该同上。
后代类定义体中:
派生类可以转换为基类;
后代类可以转换为基类(注意:在构造函数和复制控制成员中的限制和派生类中一样);
派生类用户代码中:
派生类无法转换为基类;
后代类无法转换为基类;
当为private派生时:
派生类定义体中:
由于派生列表中的访问标号只对用户代码和后代派生类有影响,对派生类访问基类成员没有影响,所以,此处情况应该同上。
后代类定义体中:
派生类无法转换为基类;
后代类无法转换为基类;
用户代码中:
派生类无法转换为基类;
后代类无法转换为基类;
下面是用来做试验的类层次,只举出几个例子。实际在试验过程中,每次只试验一种情况,试验完毕马上擦掉,以免影响接下来的试验结果。
class A
{
public:
A(const int &ru = 0)
: base(ru) {}
A(const A &pp)
: base(pp.base) { A w; A s(w); } //试验复制控制函数里的情况,就是在这里面加定义和转换代码,这个
virtual ~A() {} //示例在用户使用此函数时会出错。例在main()中执行 A a; A b(a)。
private:
int base;
protected:
};
class B :private A
{
public:
B(const int &ru = 0, const int &ru2 = 0)
: A(ru), bulk(ru2) { B a; } //试验构造函数里的情况,在这里加代码。这个示例,当用户在main()中定义B a;时就会出错。
~B() { B b; } //试验析构函数里的情况,在这里加代码。这个示例,在发生此类型的析构时就会出错。
private:
int bulk;
protected:
};
class C : public B
{
public:
C(const int &ru = 0, const int &ru2 = 0, const int &ru3 = 0)
: B(ru, ru2), bulk2(ru3) {}
void uuuu() { A a; B b; C c; a = b; a = c; } //试验其它函数里面的情况,在这里面加定义的转换代码,此示例可行,不会出现错误。
~C() {}
private:
int bulk2;
protected:
};
总结:在可以访问到基类public成员的地方,可以进行派生类到基类的转换。
在用visual studio 2008试验上述规则时,发现在类定义体中,构造函数里面不能定义本身类的对象,否则在用户代码中使用时,运行会出现错误;析构函数里面也不能定义本身类对象,运行时会出现错误;在复制函数里可以定义本身类对象,在这个函数内部不能使用本身的复制功能,否则运行时同样会出错;在赋值函数里也可以定义本身类对象,在这个函数里面也不能使用本身类的赋值功能,否则还是会出错;
在其它成员函数里面可以定义本身类的对象,也能使用复制控制功能。
在类定义体内,不属于成员函数的范围,只能定义本身类的指针或引用。