多态
-
默认情况下,编译器只会根据指针类型调用对应的函数,不存在多态
-
多态是面向对象非常重要的一个特性
- 同一操作作用于不同的对象,可以有不同的解释,产生不同的执行结果
- 在运行时,可以识别出真正的对象类型,调用对应子类中的函数
-
多态的要素
- 子类重写父类的成员函数(override)
- 父类指针指向子类对象
- 利用父类指针调用重写的成员函数
虚函数
- C++中的多态通过虚函数(virtual function)来实现
- 虚函数:被virtual修饰的成员函数
- 只要在父类中声明为虚函数,子类中重写的函数也自动变成虚函数(也就是说子类中可以省略virtual关键字)
虚表
虚函数的实现原理是虚表,这个虚表里面存储着最终需要调用的虚函数地址,这个虚表也叫虚函数表
struct Animal {
int m_age;
virtual void speak(){
cout << "Animal::speak()" << endl;
}
virtual void run(){
cout << "Animal::run()" << endl;
}
};
struct Cat: Animal {
int m_life;
virtual void speak(){
cout << "Cat::speak()" << endl;
}
virtual void run(){
cout << "Cat::run()" << endl;
}
};
int main() {
Animal *cat =new Cat();
cat->speak();
cat->run();
return 0;
}
// log:
Cat::speak()
Cat::run()
注意,一定要指针,如果是对象,就失灵了。多态的三要素缺一不可。
int main() {
Animal cat = Cat();
cat.speak();
cat.run();
return 0;
}
// log:
Animal::speak()
Animal::run()
虚表(x86环境的图)
调用父类的成员函数实现
class Animal {
public:
virtual void speak(){
cout << "Animal::speak()" << endl;
}
};
class Cat: public Animal {
public:
void speak(){
Animal::speak();
cout << "Cat::speak()" << endl;
}
};
int main() {
Animal cat = Cat();
cat.speak();
return 0;
}
// log:
Animal::speak()
Q:为啥不继续执行下面的代码
A:上面不是多态
int main() {
Animal *cat = new Cat();
cat->speak();
return 0;
}
// log:
Animal::speak()
Cat::speak()
虚析构函数
- 含有虚函数的类,应该将析构函数声明为虚函数(虚析构函数)
- delete父类指针时,才会调用子类的析构函数,保证析构的完整性
class Animal {
public:
virtual void speak(){
cout << "Animal::speak()" << endl;
}
virtual ~Animal(){
cout << "Animal::~Animal()" << endl;
}
};
class Cat: public Animal {
public:
void speak(){
Animal::speak();
cout << "Cat::speak()" << endl;
}
~Cat(){
cout << "Animal::~Cat()" << endl;
}
};
int main() {
Animal *cat = new Cat();
cat->speak();
return 0;
}
// log:
Animal::speak()
Cat::speak()
Q:为啥不析构
网友评论