目录
一,多态及虚函数
构成多态条件
虚函数
override和final(C++11)
重载、重写(覆盖)、隐藏(重定义)对比
二,抽象类
接口继承和实现继承
三,多态原理
动态绑定和静态绑定
四,单继承和多继承关系的虚函数表
单继承中虚函数表
多继承中虚函数表
菱形继承、菱形虚拟继承
一,多态及虚函数
构成多态条件
虚函数
虚函数重写(覆盖)
class Person
{
public:
virtual void BuyTicket() {cout << "No discount!" << endl;}
};
class Stu :public Person
{
public:
virtual void BuyTicket() {cout << "Half discount!" << endl;}
};
void Func(Person& person) {person.BuyTicket();}
int main()
{
Person person;
Stu stu;
Func(person);
Func(stu);
return 0;
}
注:重写基类虚函数时,派生类的虚函数可不加virtual关键字,虽然也构成重写(因继承后基类的虚函数被继承下来了在派生类依旧保持虚函数属性),但这种写法不规范,不建议使用;
虚函数重写的两个例外
//协变
class A{};
class B:public A{};
class Person
{
public:
virtual A* BuyTicket()
{
cout << "No discount!" << endl;
return new A;
}
};
class Stu :public Person
{
public:
virtual B* BuyTicket()
{
cout << "Half discount!" << endl;
return new B;
}
};
void Func(Person& person) {person.BuyTicket();}
int main()
{
Person person;
Stu stu;
Func(person);
Func(stu);
return 0;
}
//析构函数重载
class Person
{
public:
virtual ~Person() {cout << "~Person()" << endl;}
};
class Stu :public Person
{
public:
virtual ~Stu() {cout << "~Stu()" << endl;}
};
int main()
{
Person* p1 = new Person;
Person* p2 = new Stu;
delete p1;
delete p2;
return 0;
}
override和final(C++11)
C++对函数重写的要求比较严格,如函数名字母次序写反即无法构成重载,而这种错误在编译期间无法识别,只有在程序运行时没有得到预期结果才会发现得不偿失;因此C++11提供了关键字override和final,可帮助检测是否重写了;
final
class Car final{};
//不可将final类作为基类
class Benz :public Car {};
class Car
{
public:
virtual void Drive() final {cout << "Car" << endl;}
};
class Benz :public Car
{
public:
//报错,无法重写final函数
virtual void Drive() {cout << "Benz" << endl;}
};
override
class Car
{
public:
virtual void Drive() {cout << "Car" << endl;}
};
class Benz :public Car
{
public:
//报错,没有重写基类成员
virtual void Dri() override {cout << "Benz" << endl;}
};
重载、重写(覆盖)、隐藏(重定义)对比
重载
class fatherA
{
public:
void print() { cout << "->" << " fatherA " << endl; }
void print(int) { cout << "->" << " fatherA(int) " << endl; }
};
重写(覆盖)
class fatherA
{
public:
virtual void print() { cout << "->" << " fatherA " << endl; }
};
class childB :public fatherA
{
public:
virtual void print() { cout << "->" << " childB " << endl; }
};
隐藏(重定义):
class fatherA
{
public:
void print() { cout << "->" << " fatherA " << endl; }
};
class childB :public fatherA
{
public:
void print() { cout << "->" << " childB " << endl; }
};
二,抽象类
概念:
接口继承和实现继承
class Car
{
public:
virtual void Drive() = 0; //纯虚函数
};
class Benz :public Car
{
public:
virtual void Drive() {cout << "Benz" << endl;}
};
class BMW :public Car
{
public:
virtual void Drive() {cout << "BMW" << endl;}
};
void fun(Car& car) {car.Drive();}
int main()
{
//Car car; //抽象类不可实例化对象
Benz benz;
BMW bmw;
fun(benz);
fun(bmw);
Car* pbenz = new Benz;
Car* pbmw = new BMW;
pbenz->Drive();
pbmw->Drive();
return 0;
}
三,多态原理
class Car
{
public:
virtual void fun() { cout << "fun()" << endl; }
protected:
int _car;
};
int main()
{
Car car;
cout << sizeof(car) << endl; //结果为8
return 0;
}
上述案例结果为8,是因为除了成员变量_car,还有一个成员 _vfptr(在_car前面还是后面和平台有关),对象中的成员_vfptr为指针类型,叫做虚函数表指针;一个包含虚函数的类中,至少有一个虚函数表指针;虚函数表简称虚表,是存放该类所有虚函数地址的数组;
class Car
{
public:
virtual void fun1() { cout << "fun1()" << endl; }
virtual void fun2() { cout << "fun2()" << endl; }
void fun3() { cout << "fun3()" << endl; }
protected:
int _car;
};
class Benz :public Car
{
public:
virtual void fun1() { cout << "Benz::fun1()" << endl; }
protected:
int _benz;
};
int main()
{
Car car;
Benz benz;
return 0;
}
满足多态以后的函数调用,是运行后到对象中去找的;
不满足多态的函数调用,是编译时就确认好的;
动态绑定和静态绑定
四,单继承和多继承关系的虚函数表
单继承中虚函数表
class Car
{
public:
virtual void fun1() { cout << "fun1()" << endl; }
virtual void fun2() { cout << "fun2()" << endl; }
protected:
int _car;
};
class Benz :public Car
{
public:
virtual void fun1() { cout << "Benz::fun1()" << endl; }
virtual void fun3() { cout << "Benz::fun3()" << endl; }
virtual void fun4() { cout << "Benz::fun4()" << endl; }
protected:
int _benz;
};
typedef void(*VFPTR)(); //函数指针
void PrintVTable(VFPTR vtable[])
{
cout << "虚表地址->" << vtable << endl;
for (int i = 0; vtable[i] != nullptr; ++i)
{
printf("第%d个虚函数地址: 0X%x->", i, vtable[i]);
VFPTR f = vtable[i];
f();
}
cout << endl;
}
int main()
{
Car car;
Benz benz;
//思路:取对象头4个字节,即是虚表指针,虚表是存虚函数指针的指针数组,最后为nullptr;
//运行时可能会崩溃,是因为编译器对虚表处理不干净,编译器问题,在点击菜单栏生成-清理解决方案;
VFPTR* vtable_car = (VFPTR*)(*(int*)&car);
PrintVTable(vtable_car);
VFPTR* vtable_benz = (VFPTR*)(*(int*)&benz);
PrintVTable(vtable_benz);
return 0;
}
多继承中虚函数表
class Car1
{
public:
virtual void fun1() { cout << "Car1::fun1()" << endl; }
virtual void fun2() { cout << "Car1::fun2()" << endl; }
protected:
int _car1;
};
class Car2
{
public:
virtual void fun1() { cout << "Car2::fun1()" << endl; }
virtual void fun2() { cout << "Car2::fun2()" << endl; }
protected:
int _car2;
};
class Benz :public Car1, public Car2
{
public:
virtual void fun1() { cout << "Benz::fun1()" << endl; }
virtual void fun3() { cout << "Benz::fun3()" << endl; }
protected:
int _benz;
};
typedef void(*VFPTR) ();
void PrintVTable(VFPTR vtable[])
{
cout << "虚表地址->" << vtable << endl;
for (int i = 0; vtable[i] != nullptr; ++i)
{
printf("第%d个虚函数地址: 0X%x->", i, vtable[i]);
VFPTR f = vtable[i];
f();
}
cout << endl;
}
int main()
{
Benz benz;
VFPTR* vtable_benz_car1 = (VFPTR*)(*(int*)&benz);
PrintVTable(vtable_benz_car1);
VFPTR* vtable_benz_car2 = (VFPTR*)(*(int*)((char*)&benz+sizeof(Car1)));
PrintVTable(vtable_benz_car2);
return 0;
}
菱形继承、菱形虚拟继承