什麼是純虛函數
純虛函數是一種特殊的虛函數,前面分析過虛函數,虛函數是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;
}
由上面的例子可以得出:
- 多重繼承接口不會帶來二義性和複雜性等問題
- 多重繼承可以通過精心設計用單繼承和接口來代替
- 接口類只是一個功能說明,而不是功能實現。
- 子類需要根據功能說明定義功能實現。