抽象方法(abstract method),也可以称为纯虚函数,是面向对象编程技术的另一个核心概念,在设计一个多层次的类继承关系时市场会用到。
把某个方法声明为一个抽象方法等于告诉编译器这个方法必不可少,但我现在(在这个基类里)还不能为它提供一个实现!
上一个例子里有一个Pet::play(),在当时把每一个都输,但是在现实中不存在什么都玩的宠物,每种宠物都有自己的玩法,而我们的应对措施是输出一条消息说宠物正在玩。
现在既然知道了抽象方法这个概念,我们就再也用不着编写那些不必要的代码了
抽象方法的语法很简单:在声明一个虚方法的基础上,在原型的末尾加上“=0”。(告诉编译器不用浪费时间再这个类里寻找这个方法的实现!)
来个例子:
#include <iostream>
#include <string>
class Pet
{
public:
Pet(std::string theName);
virtual void eat();
virtual void sleep();
virtual void play() = 0;
//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 << "正在吃!" << std::endl;
}
void Pet::sleep()
{
std::cout << name << "正在睡!" << std::endl;
}
Cat::Cat(std::string theName) : Pet(theName)
{
}
void Cat::climb()
{
std::cout << name << "正在爬树!" << std::endl;
}
void Cat::play()
{
std::cout << name << "正在玩狗头!" << std::endl;
}
Dog::Dog(std::string theName) : Pet(theName)
{
}
void Dog::bark()
{
std::cout << "正在叫!" << std::endl;
}
void Dog::play()
{
std::cout << "正在玩猫头!" << std::endl;
}
int main()
{
Pet *cat = new Cat("加菲");
Pet *dog = new Dog("李顺");
cat->eat();
cat->sleep();
cat->play();
dog->eat();
dog->sleep();
dog->play();
delete cat;
delete dog;
return 0;
}
多态性
多态性是面向对象程序设计的重要特征之一。
简单的说,多态性是指用一个名字定义不同的函数,调用同一个名字的函数,却执行不同的操作,从而实现传说中的“一个接口,多重方法!”
多态是如何实现绑定的?
- 编译时多态性:通过重载
- 运行时多态性:通过虚函数
编译时的多态性的特点是运行速度快,运行时的特点是高度灵活和抽象。
析构函数解析
为什么所有的析构器都是虚函数
#include <iostream>
#include <string>
class ClxBase
{
public:
ClxBase()
{
}
virtual ~ClxBase()
{
}
virtual void doSomething()
{
std::cout << "Do something in class ClxBase" << std::endl;
}
};
class ClxDerived : public ClxBase
{
public:
ClxDerived()
{
}
~ClxDerived()
{
std::cout << "Output from the destructor of class ClxDerived" << std::endl;
}
void doSomething()
{
std::cout << "Do something in class ClxDerived" << std::endl;
}
};
int main()
{
ClxBase *pTest = new ClxDerived;
pTest->doSomething();
delete pTest;
return 0;
}
输出
当把ClxBase析构函数钱的virtual去掉,那输出的结果就变成了
也就是说ClxDerived的析构函数没有被调用到!
总结
一般下类的析构函数里面都是释放内存资源,而析构函数不被调用的话就会造成内存泄漏
所以,析构器都是虚方法是为了当一个基类的指针删除一个派生类的对象时,派生类的析构函数可以被正确调用。
另外,当类里面有虚函数的时候,编译器会给类添加一个虚函数表,里边存放这虚函数指针。为了节省资源,只有当一个类被用作基类的时候,我们才把析构函数写成虚函数。