面向对象编程
Inheritance继承 Composition复合 Delegation委托
Composition(复合) 表示 has a
- Container -> Component
构造由内而外进行,Container的构造函数首先调用Component的default构造函数,然后才执行自己。(即由编译器默认再初始化列表中调用Component的构造函数)
Container::Container(...):Component(){...}
析构由外而内,Container的析构函数先执行自己,然后在调用Component的析构函数(即由编译器默认在Container的析构函数的最后调用Component的析构函数)
Container::~Container(...){... ~Component(); }
Delegation(委托).Composition by reference.Handle/Body模式(编译防火墙模式)
- 在类内有一个指向具体实现类的指针,类只提供一个调用的接口而不负责具体实现,这样可以通过让指针指向不同的具体实现类来改变具体实现而不用影响客户端,也不用全部重新编译。
Inheritance(继承),表示Is a
- Derived -> Base
构造由内而外进行,Derived的构造函数首先调用Base的default构造函数,然后才执行自己。(即由编译器默认再初始化列表中调用Base的构造函数)
Derived::Derived(...):Base(){...}
析构由外而内,Container的析构函数先执行自己,然后在调用Base的析构函数(即由编译器默认在Derived的析构函数的最后调用Base的析构函数)
Derived::~Derived(...){... ~Base(); }
base class的dtor必须是virtual,否则会出现undefined behavior
继承应配合virtual函数来使用。
如果函数没有使用关键字virtual修饰,则程序将根据对象、引用类型或指针类型调用函数。如果使用virtual修饰函数则程序将根据引用或者指针 指向的对象类型 进行选择方法。但是将函数定义成virtual会增加程序的空间和时间开销。在基类方法的声明中使用关键字virtual可是该方法在基类以及所有的派生类(包括从派生类派生出来的类)中是虚的。
- 为基类声明一个虚析构函数是一种惯例(除非它不做基类),这样可以确保释放派生对象时按正确的顺序调用析构函数。如果虚构函数不是虚的则指挥调用指针类型的析构函数,而不会调用指针指向的类型的析构函数,这样会出现错误。
- 在派生类中的虚函数调用基类的同名虚函数时需要使用基类类名域作用符,否则会出现无限循环调用。
- 派生类不能直接访问基类的private成员和方法,必须通过protected或者public来进行访问。
- 构造函数不能是虚函数。(没有意义)
- 友元函数不能是虚函数,因为友元函数不是类成员。
- 在类的虚函数声明后面加
=0
即将此函数定义为纯虚函数,包括纯虚函数的类为抽象基类(abstract base class ,ABC)。抽象基类不能创建该类的对象。由抽象基类派生出来的类成为具体类(concrete)。可以将ABC看成一种必须实施的接口。
- 当基类 和派生类都采用动态内存分配时,派生类的析构函数、复制构造函数、赋值运算符函数都必须使用相应基类方法来处理基本元素。对于析构函数这是自动完成的;对于构造函数,这是通过在初始化列表中调用街垒的复制构造函数来完成的(如果不这样做,将自动调用 基类的默认构造函数);对于赋值运算符,这是通过使用作用域解析运算符显示调用基类的赋值运算符来完成的。例如:
class baseDMA {
private:char * point;
...
}
baseDMA& baseDMA::operator= (const baseDMA& rs) {
if(this==&rs) return *this;
delete[] point;//释放动态分配的内存
...//重新动态分配内存,复制内容
return *this;
}
class hasDMA :public baseDMA{
private: char * point2;
...
}
hasDMA& hasDMA::operator= (const hasDMA& rs) {
if(this==&rs) return *this;
baseDMA::operator=(hs);//复制基类部分
/*通过使用函数方式显示调用基类的赋值函数作用类似于
*this=rs;只不过如果不使用函数方式就没法使用域作用符,
此时函数会默认调用hasDMA::operator=(),从而形成无限递归调用*/
delete[] point2;
...//动态分配内存,复制内容
return *this;
}