虚方法:
1、声明虚方法的语法非常简单,只要在其原型前边加上virtual保留字即可;
virtual void play();
2、普通函数是静态绑定,在编译的时候就确定了要调用基类的函数;虚函数是动态绑定,在运行的时候才确定是调用基类的函数还是子类的函数;
3、另外,虚方法是继承的,一旦在基类里把某个方法声明为虚方法,在子类里就不可能再把它声明为一个非虚方法了;
4、这对于程序设计来说是一件好事,因为这可以让程序员无需顾虑一个虚方法会在某个子类里变成一个非虚方法;
注意:
1、如果拿不准要不要把某个方法声明为虚方法,那么最好把它声明为虚方法;
2、在基类里把所有的方法都声明为虚方法会让最终生成的可执行代码的速度变得稍微慢一些,但好处是可以一劳永逸地确保程序的行为符合预期;
3、在实现一个多层次的类继承关系的时候,最顶级的基类应该只有虚方法;
4、析构器都是虚方法,从编译的角度看,他们只是普通的方法。如果他们不是虚方法,编译器就会根据它们在编译时的类型而调用那个在基类里定义的版本(构造器),那样的话有可能会导致内存泄露。
举例:
#include <iostream>
#include <string>
class Pet
{
public:
Pet(std::string theName);
void eat();
void sleep();
virtual void play();
protected:
std::string name;
};
class Cat : public Pet
{
public:
Cat(std::string theName);
void climb();
void play();
};
class Dog : public Pet
{
public:
Dog(std::string theName);
void bark();
void play();
};
Pet::Pet(std::string theName)
{
name = theName;
}
void Pet::eat()
{
std::cout << name << "正在吃东西!\n";
}
void Pet::sleep()
{
std::cout << name << "正在睡大觉!\n";
}
void Pet::play()
{
std::cout << name << "正在玩儿!\n";
}
Cat::Cat(std::string theName) : Pet(theName)
{
}
void Cat::climb()
{
std::cout << name << "正在爬树!\n";
}
void Cat::play()
{
Pet::play();
std::cout << name << "玩毛线球!\n";
}
Dog::Dog(std::string theName) : Pet(theName)
{
}
void Dog::bark()
{
std::cout << name << "旺~旺~\n";
}
void Dog::play()
{
Pet::play();
std::cout << name << "正在追赶那只该死的猫!\n";
}
int main()
{
Pet *cat = new Cat("加菲");
Pet *dog = new Dog("欧迪");
cat -> sleep();
cat -> eat();
cat -> play();
dog -> sleep();
dog -> eat();
dog -> play();
delete cat;
delete dog;
return 0;
}
当Pet基类使用普通方法void play();时,输出:
加菲正在睡大觉!
加菲正在吃东西!
加菲正在玩儿!
欧迪正在睡大觉!
欧迪正在吃东西!
欧迪正在玩儿!
当Pet基类使用虚方法virtual void play();时,输出:
加菲正在睡大觉!
加菲正在吃东西!
加菲正在玩儿!
加菲玩毛线球!
欧迪正在睡大觉!
欧迪正在吃东西!
欧迪正在玩儿!
欧迪正在追赶那只该死的猫!