1.对类的成员函数加 virtual 和不加 virtual的区别
看这么一个例子
class Animal {
public:
void makeSound() {
cout << "Animal sound!" << endl;
}
};
class Dog: public Animal {
public:
void makeSound() {
cout << "Bark!" << endl;
}
};
int main() {
Animal* a = new Dog;
a->makeSound(); // Animal sound!
Dog* d = new Dog;
d->makeSound(); // Bark!
}
此时输出:
也就是说尽管基类指针指向子类对象,但是调用的还是基类指针的行为。
而将 makeSound声明为virtual时:
class Animal {
public:
virtual void makeSound() {
cout << "Animal sound!" << endl;
}
};
class Dog: public Animal {
public:
void makeSound() {
cout << "Bark!" << endl;
}
};
int main() {
Animal* a = new Dog;
a->makeSound(); // Animal sound!
Dog* d = new Dog;
d->makeSound(); // Bark!
}
此时才会出现多态的行为,即基类指针指向子类对象会调用子类的行为。
2.对类的析构函数函数加 virtual 和不加 virtual的区别:
对析构函数不加virtual
例子:
#include<iostream>
using namespace std;
class Base {
public:
~Base() {
cout<<"Base deconstructor"<<endl;
} // 析构函数
};
class Derived: public Base {
int *p;
public:
Derived() {
p = new int(10);
}
~Derived(){
delete p;
cout<<"Derived deconstructor"<<endl;
}
};
int main(){
Derived *d = new Derived();
Base *b = new Derived();
delete d; // 只释放Base中的内存,不释放p
cout<<endl;
delete b;
}
此时输出结果为:
可以看到如果是子类指针指向子类对象
先调用自己的析构函数,再调用基类的析构函数
但如果是基类指针指向子类对象
,则只调用基类的析构函数
当加上virtual后:
#include<iostream>
using namespace std;
class Base {
public:
virtual ~Base() {
cout<<"Base deconstructor"<<endl;
} // 析构函数
};
class Derived: public Base {
int *p;
public:
Derived() {
p = new int(10);
}
~Derived(){
delete p;
cout<<"Derived deconstructor"<<endl;
}
};
int main(){
Derived *d = new Derived();
Base *b = new Derived();
delete d; // 只释放Base中的内存,不释放p
cout<<endl;
delete b;
}
输出:
此时delete 基类指针
时,可以发现子类的析构函数调用。
3.总结
不加virtual: 只释放基类内存,执行基类语义
加 virtual: 释放派生类和基类内存,并且先执行派生类重写的语义