不用虚函数
#include <iostream>
class A {
public:
void output() {
std::cout << "I am parent." << std::endl;
}
};
class B: public A {
public:
void output() {
std::cout << "I am child." << std::endl;
}
};
int main() {
std::shared_ptr<A> target1 = std::make_shared<B>();
target1->output();
std::shared_ptr<B> target2 = std::make_shared<B>();
target2->output();
return 0;
}
I am parent.
I am child.
用虚函数
#include <iostream>
class A {
public:
// 只有这里不同,这里加了virtual
virtual void output() {
std::cout << "I am parent." << std::endl;
}
};
class B: public A {
public:
void output() {
std::cout << "I am child." << std::endl;
}
};
int main() {
std::shared_ptr<A> target1 = std::make_shared<B>();
target1->output();
std::shared_ptr<B> target2 = std::make_shared<B>();
target2->output();
return 0;
}
I am child.
I am child.
分析
同样是指向B对象的指针,在运行期间,为什么没有加virtual的函数调用的却是父类函数,而没有加的调用的就是子类函数?
这里需要了解一个重要的概念——虚函数表,所有的虚函数都会存储在这个表里面。当我们给C++的指针赋予某一个类型的时候,其实并没有改变内存里面的任何东西,改变的只是解释内存的方式。现在A对象应为有了virtual,在实例化的时候就会初始化一个虚函数指针,和对应的额虚函数表,同时还有对应的内容——虚函数output()。
我们在实例化B对象的时候,虚函数表里面实际存放B对象的output实现。这样在调用的时候,就能从父类指针指向的内存里面,先找到虚函数指针,再找到虚函数表,从而完成对子类的调用,而这也就是多态的作用。
但如果没有virtual的时候,因为没有虚函数表,也就无法找到子类的实现。那么利用父类本身的内存空间描述,只能调用父类的函数了。
思考题
有纯虚函数的类为什么不能实例化?
纯虚函数是没有实现的,如果一个声明了纯虚函数的类被实例化,调用的时候应该如何处理是个问题,这样不如干脆禁止掉。
虚继承是怎么回事
虚拟继承在一般的应用中很少用到,所以也往往被忽视,这也主要是因为在C++中,多重继承是不推荐的,也并不常用,而一旦离开了多重继承,虚拟继承就完全失去了存在的必要因为这样只会降低效率和占用更多的空间。
参考:https://www.cnblogs.com/BeyondAnyTime/archive/2012/06/05/2537451.html