C++ Primer Plus Chapter13

Chapter13 类继承

派生类

公有派生

class A : public class B

派生类继承基类的公有成员和私有成员,但私有成员只能通过 publicprotected 方法访问

创建派生类对象时,程序首先创建基类对象。派生类对象过期时,首先调用派生类析构函数,再调用基类析构函数。

构造函数必须给新成员和集成的成员提供数据。

基类指针和引用可以指向派生类对象

多态公有继承

例:

class a{
  public:
    void method_1(){
		std::cout << "A";
	};
    virtual void method_2(){
		std::cout << "C";
	}
}
class b : public a{
  public:
    void method_1(){
		std::cout << "B";
	};
	virtual void method_2(){
		std::cout << "D";
	}
}

如果方法前没有 virtual 关键字,那么将通过指针的类型或引用的类型确定调用的方法

如果方法前加了 virtual 关键字,那么将通过指针指向对象的类型或引用的对象的类型来确定调用的方法

静态联编和动态联编

强制转换

  1. 向上强制转换:将派生类引用或指针转换为基类的引用或指针
  2. 向下强制转换:将基类引用或指针转换为派生类的引用或指针(必须进行显示转换)

静态联编、动态联编

编译器对于非虚方法使用静态联编,对于虚方法使用动态联编。

默认为静态联编的取舍: 为了实现动态联编需要花费开销用于追踪基类指针或引用的对象类型,但对于一个类如果不作为基类,或者其中一些方法不会被派生类重写,那么这种开销是不必要的,因此在这种情况下使用静态联编效率更高,将静态联编设置为默认。

虚函数原理

一种虚函数机制

编译器会给每一个对象添加一个虚函数地址表,将每一个虚函数的地址存储在这个表中。派生类会新创建一个这样的虚函数地址表,它保存基类的虚函数地址,将其中被重写的虚函数地址修改为新函数地址,同时添加自身新定义的虚函数。这样在指针或引用调用函数时,就会查看该对象的虚函数表来决定调用基类还是自身的函数。

注意事项

  1. 构造函数不能是虚函数,因为派生类构造对象时,派生类的构造方法会调用基类的构造方法,并不继承基类的构造函数,所以声明为虚方法没有意义。
  2. 析构函数应该为虚函数,派生类对象在过期时,如果调用自身的析构函数,那么会正常先释放自身的内存,再调用基类析构函数释放基类对象的内存。但如果不是虚方法,那么就根据静态联编只调用了基类的析构函数释放了基类对象的内存,没有释放派生类新的成员所占的内存。
  3. 友元不能是虚函数,因为友元不是类成员。
  4. 如果派生类没有重写函数,将使用该函数的基类版本。
  5. 在派生类中重新定义方法,不会生成重载,而是将所有同名基类函数都隐藏。

参考书目C++ Primer Plus 第6版