赞
踩
如果想实现不同的类的对象调用不同的虚函数
可以通过 协变 这种形式
在父类Person中的虚函数的返回值 的数据类型是一个 父类(任意一个父类σ就行)
在子类Student中的虚函数的返回值 的数据类型是一个 继承了σ的子类
- class Student : public Person
- {
- public:
- virtual B* BuyTicket()
- {
- cout << "买票-半价" << endl;
- return nullptr;
- }
- //如果不写 virtual 下述析构函数
- //那么只要定义一个 非Student 类型的对象,就无法调到~Student()这个函数
- //导致 _ptr无法释放空间
- virtual ~Student()
- {
- delete[] _ptr;
- cout << "~Student()" << endl;
- }
- private:
- int* _ptr = new int[10];
- };
- //实际上 父子类 中析构函数的函数名最终会处理成一样的
- //那么是否应该使用virtual来修饰自定义的 父子类中的析构函数呢?
- int main()
- {
- Person* p1 = new Person;
- Person* p2 = new Student;
-
- //delete这条指令代表了 析构函数 和 operator delete(p1)
- //delete在调用析构函数的时候只会看两点
- /*1. 根据指针的类型,如果是Person类型的指针,
- 此时无论指向的是什么,都会调用Person这个类中的析构函数 ~Person
- 2. 根据父子类中有没有对应的 自定义 虚 的析构函数
- 如果有,且构成多态,那么就是指向谁,析构谁,
- 比如上述的代码中p2指向的是一个Student对象,
- 那么此时delete p2,将会调用Student的析构函数 virtual ~Student()
-
- 注意!!!!!!!!!!!!!!!!!!!!!!!!
- 一、如果只通过 1 来调用析构函数,那么可能会造成无法调到指定类型的析构函数问题
- 这是因为指针的类型不一定和 所指向的 数据类型相同
- 根据指针类型 来调用 析构函数
- 那么只能通过 在父子类中对析构函数分别加上 virtual
- 二、上述一、中给父子类的析构函数加上 virtual就能构成多态的原因是:
- 编译器会把所有析构函数都处理成同名同参的函数,都改成destructor()的函数
- 以方便这两个函数构成重写*/
- delete p1;
- delete p2;
-
- return 0;
- }
综上,虚函数virtual的使用有三个例外
1. 协变:父子类中不完全三同, 返回值类型 是父子类
2. 父子类中析构函数都加上virtual
3. 子类中的虚函数可以不加virtual
例题1:
对于下面的程序,其执行结果是 B->1,需要注意的是
1. 首先有一个指p 指向了 一个B 类对象,
对于p->test(); 值得说明的是:
1.1 由于 p 是一个 B类型的指针,所以 会在 B 类型中寻找一个名叫test()的成员函数
1.2 B类继承了A,要找到test(),也可以从 A 类中寻找
2. A类中的test()要调用 func(),那么需要问,构不构成多态调用?
构成,这是因为:
2.1 父类和子类中都有func,且返回值,且参数类型相同,且父类中的func用virtual修饰
2.2 调用func的时候是通过 A类中this指针进行调用的,
值得注意的是:
this指针的数据类型是 A*,这是因为test()是属于A这个类域的
所以构成多态调用
3. 基于2.,由于A::this->func();构成多态调用
所以会根据 指针指向的对象来确定调用哪个函数,
注意:和什么类型的指针没有关系,只取决于被指向的数据类型,
也就是只取决于一开始在调用test()这个函数时,
写下σ->test()的这个σ究竟是什么类型,对于下面的程序
σ的类型是有new B 来决定的,σ的类型是B
所以应该调用B中的func函数
4. 虽然会执行 cout << "B->" << val << endl; 的这个定义
但是函数的声明是 virtual void func(int val = 1)
这就是多态调用的特点,需要按照3. 先找到σ的类型,把这个类型中的func找到后
把其中的实现代码 重写 到 2.中用 this 指针进行调用的 func() 函数中
也就是 (根据2.) 使用 A 中func的声明,(根据3.) 使用 B 中 func的定义
例题2:
多继承中由于public Base1, public Base2 表明
Base1比Base2先继承,那么Base1 的会先开空间
所以Base1先开空间,Base2后开空间
Derive会指向包含父类空间和子类所需空间的一开始,
所以 p3 指针变量的值和 p1 指针变量的值相同,且小于p2
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。