目录
1.虚函数
- 多态是通过虚函数来实现的,虚函数允许子类重定义父类的成员函数。
- 虚函数的动态绑定:基类指针可以指向基类对象或派生类对象,所以只能是动态绑定,当程序运行的时候才知道其基类指针指向的是基类对象还是派生类对象。
- 如果定义了虚函数,则最好将析构函数也定义为虚函数。这样才可以先调用派生类的析构函数,再调用基类的析构函数。
- 构造函数不能是虚函数的原因:
虚函数机制只有在应用于地址时才有效,因为地址在编译阶段提供的类型信息不完全。构造函数的功能是为一个对象在内存中分配空间,也就是说,此时该对象的类型已经确定了,编译系统确切的知道应该调用哪一个类的构造函数,不需要也不可能应用动态绑定。
2.纯虚函数
- 纯虚函数只声明不定义。函数原型之后加=0即可。
- 包含纯虚函数的类称为抽象类,这就意味着不能生成抽象类对象。
- 在成员函数内可以调用纯虚函数
- 在构造函数/析构函数内部不能调用纯虚函数。
3.虚函数表
- 每个含有虚函数的类都会维护一张虚函数表,表中的每一项是该类中虚函数的地址。
- 由于涉及到虚函数表和虚基表,会同时增加一个(多重虚继承下对应多个)vfPtr指针指向虚函数表vfTable和一个vbPtr指针指向虚基表vbTable,这两者所占的空间大小为:8。
4.注意
- 友元关系不能继承。基类的友元对派生类的成员没有特殊访问权限。如果基类被授予友元关系,则只有基类具有特殊访问权
限,该基类的派生类不能访问授予友元关系的类 - 如果基类定义 static 成员,则整个继承层次中只有一个这样的成员。无论从基类派生出多少个派生类,每个 static 成员只有一个实例。
5.代码示例
#include <iostream>
using namespace std;
class A
{
public:
A(short val1 = 1, short val2 = 2):data1(val1),data2(val2) {} //构造函数不能调用虚函数
A() {} //构造函数不能调用虚函数
~A() {}
virtual void fun1() //虚函数
{
cout << "A::fun1 is called" << endl;
}
virtual void fun2() = 0; //纯虚函数
void fun3() //成员函数调用虚函数
{
fun1();
}
protected:
short data1;
short data2;
};
class B :public A
{
public:
B(short val1 = 1, short val2 = 2,double val3 = 3) :A(val1, val2),data3(val3){}
~B() {}
virtual void fun1() //virtual可以省略
{
cout << "B::fun1 is called" << endl;
}
virtual void fun2()
{
cout << "B::fun2 is called" << endl;
}
protected:
double data3;
};
int main()
{
//A a; //错误:类A是抽象类,不能实例化
B b(4, 5, 6);
A * a = &b;
//a->fun3();
cout << sizeof(b) << endl; //2+2+4+8 = 16字节
getchar();
return 0;
}