什么是纯虚函数
纯虚函数是一种特殊的虚函数,前面分析过虚函数,虚函数是virtual修饰的类的成员函数,可以有实现。而纯虚函数也和虚函数一样,用virtual来修饰的类的成员函数,但是只能有函数体不能有具体实现。
一般格式:
class <类名>
{
virtual <类型><函数名>(<参数表>) = 0;
...
}
1、纯虚函数是一个在父类中只有函数体,没有实现,实现在子类中去完成
2、纯虚函数为各子类提供了一个公共界面(接口的封装和设计、软件的模块功能划分)
3、一个具有纯虚函数的父类也称为抽象类
为什么要用到纯虚函数(抽象类)
1、为了方便使用多态特性
2、在很多情况下,父类本身生成对象是不合理的。例如,动物作为一个父类可以派生出猫、狗等子类,但动物本身生成对象明显不合理。
#pragma warning(disable : 4996)
#include <iostream>
using namespace std;
class Animal
{
public:
Animal()
{
this->m_a = 1;
cout << "Animal: 构造函数" << endl;
}
~Animal() {}
virtual void Call()
{
cout << "Animal: Call" << endl;
}
virtual void Eat() = 0;
private:
int m_a;
};
class Cat:public Animal
{
public:
Cat()
{
this->m_a = 2;
cout << "Cat: 构造函数" << endl;
}
~Cat() {}
virtual void Call()
{
cout << "Cat: Call" << endl;
}
void Eat()
{
cout << "Cat: Eat" << endl;
}
private:
int m_a;
};
//不允许使用抽象类作函数参数
//void Test(Animal a){}
int main()
{
//Animal a1;//不允许使用抽象类类型
//Animal a2();//不允许返回抽象类
//Test(a1);//不允许使用抽象类作函数参数
Animal *a = new Cat();
a->Call();
a->Eat();
Cat c;
Animal &a1 = c;
a1.Call();
a1.Eat();
printf("父类占内存大小:%d, 子类占内存大小:%d\n", sizeof(Animal), sizeof(Cat));
system("pause");
return 0;
}
如上面的例子,我们可以总结对抽象类做哪些操作是合理的:
1、可以声明抽象类的指针:Animal *cat = new Cat();
2、可以声明抽象类的引用:Animal &cat
抽象类在多继承中的应用
C++中没有接口这个概念,学过其他高级语言的朋友可能接触过了接口(协议)这个概念,那么C++中的抽象类就是模拟的这种机制。但是在继承中高级语言不能继承多个父类,可以继承多个接口,C++中没有接口这个概念,但可以继承多个类,那就是多继承概念。
绝大多数面向对象语言都不支持多继承,绝大多数面向对象语言都支持接口的概念,C++中没有接口的概念,C++中可以使用纯虚函数实现接口,接口类中只有函数原型定义,没有任何数据的定义。
class Interface1
{
public:
virtual void print() = 0;
virtual int add(int a, int b) = 0;
};
class Interface2
{
public:
virtual void print() = 0;
virtual int add(int a, int b) = 0;
virtual int minus(int a, int b) = 0;
};
class parent
{
public:
int a;
};
class Child : public parent, public Interface1, public Interface2
{
public:
void print()
{
cout << "Child::print" << endl;
}
int add(int a, int b)
{
return a + b;
}
int minus(int a, int b)
{
return a - b;
}
};
int main()
{
Child c;
c.print();
cout << c.add(3, 5) << endl;
cout << c.minus(4, 6) << endl;
Interface1* i1 = &c;
Interface2* i2 = &c;
cout << i1->add(7, 8) << endl;
cout << i2->add(7, 8) << endl;
system("pause");
return 0;
}
由上面的例子可以得出:
- 多重继承接口不会带来二义性和复杂性等问题
- 多重继承可以通过精心设计用单继承和接口来代替
- 接口类只是一个功能说明,而不是功能实现。
- 子类需要根据功能说明定义功能实现。