一、类的继承
派生类不继承的基类成员仅有析构函数、构造函数以及任何重载赋值运算符的成员函数。
所有其他函数成员,连同基类的所有数据成员,都将被派生类继承。
特别注意:析构函数、构造函数、重载赋值运算符是不能被派生类继承的。
1、派生类声明
class CBox
{
public:
double m_Length;
double m_Width;
double m_Height;
CBox(double lv=1.0,double wv=1.0,double hv=1.0):
m_Length(lv),m_Width(wv),m_Height(hv){};
};
class CCandyBox:CBox 默认是私有继承。等同:class CCandyBox:private CBox;
{ 如果省略基类的访问说明符,则编译器将默认该说明符
pulbic: 是private.
char* m_Contents;
CCandyBox(char* str="Candy")
{
m_Contents= new char[strlen(str)+1];
strcpy_s(m_Contents,strlen(str)+1,str);
}
~CCandyBox()
{delete[] m_Contents;};
};
2、派生类的使用
CCandyBox myCandyBox; CCandyBox共占有32个字节,其中24个字节来此基类CBox,
4个字节来此本类的char*指针,另外4个字节
是编译器要在8个字节的倍数地址上对齐成员,自动补了4个字节。
3、继承机制下的访问控制
派生类继承下了基类的所有数据,其实派生类就是父类和派生类新方法的叠加。
只是派生类不能访问父类的私有成员。
4、派生类的构造函数
虽然说派生类不会继承基类的构造函数,但它们仍然存在于基类中,并且要用于创建派
生类对象的基类部分。因为创建派生类对象的基类部分实际上属于基类构造函数而非派
生类构造函数的任务。基类的私有成员在派生类中虽然被继承下来,但是不可访问。
如果基类被声明为private,其成员在派生类中永远都不可访问。
如果基类被声明为public, 其成员在派生类中的访问级别保持不变。
如果基类被声明为protected,其成员public成员在派生类中将成为protected。
在为派生类编写构造函数时,需要初始化包括继承成员在内的派生类对象的所有成员。
5、派生类中的复制构造函数
如果给派生类定义复制构造函数,那么请在派生类复制构造函数中合理的初始化基类。
特别注意:基类中的成员变量 有动态分配的内存,那么派生类复制构造函数中一定得
调用基类复制构造函数。如果基类没有复制构造函数,那么就人工给基类添加复制构造函数。
二、友元类成员
class CBottle
{
public:
CBottle(...)
{
...
}
private:
friend CCArton; CBottle类中有了这条声明语句之后,CCarton类的
} 所有函数成员就都能自由访问CBottle类的所有数据成员。
使CCarton类成为CBottle类的友元,并不意味着CBottle类也是CCarton类的友元,人工希望如此,
则必须在CCarton类中将CBottle类声明为友元。
类友元关系还是不可继承的,人工我们以CBottle为基类定义了另一个类,则CCarton类的成员将
无权访问该派生类的数据成员,即使这些成员是从CBottle类继承的也不行。
三、虚函数
虚函数是以virtual关键字声明的基类函数。如果在基类中将某个函数指定为virtual,并且派生类
中有另外一个该函数的定义,则编译器将知道我们不想静态链接该函数,我们真正需要的是基于调
用该函数的对象种类,在程序的特定位置选择调用那个函数。
1、虚函数定义
class CBox 基类
{
public:
void ShowVolume() const
{
cout<<endl<<"CBox usable volume is"<<Volume();
}
virtual double Volume() const 虚函数定义:只要在普通函数前面加上virtual关键字即可。
{
...
}
};
class CGlassBox:public CBox 派生类
{
public:
virtual double Volume() const 虽然我们在派生类Volume()函数定义中使用了virtual关键字,
{ 但这样做不是必需的,在基类中将该函数定义为virtual已经
... 足够了。不过建议在派生类中为虚函数指定virtual关键字,
} 因为这样可以使阅读派生类定义的任何人都清楚地知道这些
}; 函数是动态选择的虚函数。
要使某个函数表现出虚函数的行为,该函数在任何派生类中都必须有与基类函数相同的名称,形参列表
和返回类型。如果基类函数是const,那么派生类中的函数也必须是const。如果使用不同的形参和返回
类型,或者将一个声明为const,而另外一个不然,则虚函数机制将不能工作。
从派生类函数的观点来看,CGlassBox派生类中的Volume()函数实际上隐藏了该函数的基类版本。
如果我们希望从某个派生类函数中调用基类的Volume()版本,则需要以CBox::Volume()这样的形式使用
作用域解析运算符来引用基类函数。
四、使用指向类对象的指针
CBox myBox(2.0,3.0,4.0);
CGlassBox myGlassBox(2.0,3.0,4.0);
CBox* pBox=0;
pBox=&myBox;
pBox->ShowVolume(); 调用的是myBox的ShowVolume函数。
pBox=&myGlassBox;
pBox->ShowVolume(); 调用的是myGlassBox的ShowVolume函数。
虚函数机制借助于指向基类的指针同样能够正常工作,实际调用的函数是基于被指向
的对象类型而选择的。
五、使用引用处理虚函数
void Output(const CBox& aBox)
{
aBox.ShowVolume();
}
CBox myBox(2.0,3.0,4.0);
CGlassBox myGlassBox(2.0,3.0,4.0);
Output(myBox); 调用的是myBox的ShowVolume函数。
Output(myGlassBox); 调用的是myGlassBox的ShowVolume函数。
class CBox; CBox类的不完整定义,好像delphi中的forword声明。
六、抽象类
1、抽象类声明
class CContainer 抽象类:包含纯虚函数的类被成为抽象类,因为
{ 我们不能定义包含纯虚函数的类的对象,抽象类存
public: 在的唯一用途,就是定义派生类。
如果抽象类的派生类将基类的纯虚函数仍然定义为纯虚函数,
在该派生类也是抽象类。
virtual double Volume() const=0; 纯虚函数。
virtual void ShowVolume() const
{
Volume();
}
};
我们已经将Volume()声明为const,所以在任何派生类中该函数的实现也都必须是const.记住,
即使名称和形参列表相同,但函数的const和非congst变体也是不同的函数,换句话说,我们
可以使用congst来重载函数。
如果我们忘记将派生类的Volume()函数指定为const,则派生类同样将仍然是抽象类,因为它
不仅包含我们定义的非const函数Volume(),还包含const纯虚函数成员Volume();
七、类类型之间的强制转换
CContainer* pContainer=new CGlassBox(2.0,3.0,4.0);
CBox* pBox=dynamic_case<CBox*>(pContainer); 将pContainer强制转换为CBox*;
CGlassBox* pGlassBox=dynamic_case<CGlassBox*>(pContainer); 将pContainer强制转换为CGlassBox*;
八、嵌套类
转载于:https://blog.51cto.com/rosehacker/449205