虚函数

虚表

虚函数的实现原理是虚表,这个虚表里面存储着最终需要调用的虚函数地址,这个虚表也叫虚函数表

class Animal {
public:
	int m_age;
	virtual void speak() {
		cout << "Animal::speak()" << endl;
	}
	virtual void run() {
		cout << "Animal::run()" << endl;
	}
};

class Cat : public Animal {
public:
	int m_life;
	Cat() :m_life(0) {}
	void speak() {
		cout << "Cat::speak()" << endl;
	}
	void run() {
		cout << "Cat::run()" << endl;
	}
};

虚表(x86环境的图)

demo

所有的Cat对象(不管在全局区、栈、堆)共用同一份虚表

思考:如果子类没有重写父类的虚函数,那么子类还有虚表吗?

class Animal {
public:
	int m_age;
	virtual void speak() {
		cout << "Animal::speak()" << endl;
	}
	virtual void run() {
		cout << "Animal::run()" << endl;
	}
};

class Cat : public Animal {
public:
	int m_life;
	Cat() :m_life(0) {}
};

答案:有,可以使用sizeof打印Cat对象的大小

思考:子类重写父类的虚函数,先执行父类中的成员函数,再执行自己的一些操作?

class Animal {
public:
	int m_age;
	virtual void speak() {
		cout << "Animal::speak()" << endl;
	}
	virtual void run() {
		cout << "Animal::run()" << endl;
	}
};

class Cat : public Animal {
public:
	int m_life;
	Cat() :m_life(0) {}
	void speak() {
		// 先执行父类中的成员函数
		Animal::speak();

		// 再执行自己的一些操作
		cout << "Cat::speak()" << endl;
	}
	void run() {
		cout << "Cat::run()" << endl;
	}
};

int main() {
	Animal *animal2 = new Cat();
	animal2->speak();
	animal2->run(); 

	getchar();
	return 0;
}

虚析构函数

含有虚函数的类,应该将析构函数声明为虚函数(虚析构函数),一般只需要在父类声明virtual即可

delete父类指针时,才会调用子类的析构函数,保证析构的完整性

class Animal {
public:
	int m_age;
	virtual void speak() {
		cout << "Animal::speak()" << endl;
	}
	virtual void run() {
		cout << "Animal::run()" << endl;
	}
	virtual ~Animal() {
		cout << "~Animal()" << endl;
	}
};

class Cat : public Animal {
public:
	int m_life;
	Cat() :m_life(0) {}
	void speak() {
		cout << "Cat::speak()" << endl;
	}
	void run() {
		cout << "Cat::run()" << endl;
	}
	~Cat() {
		cout << "~Cat()" << endl;
	}
};

思考:如果父类的析构函数不声明为虚析构函数,那么会出现什么情况?

int main() {
	Animal *cat1 = new Cat();
	cat1->speak();
	cat1->run();
    
	delete cat1;

	getchar();
	return 0;
}

如上代码,子类的析构函数~Cat()不会调用