作者:jicanmeng
时间:2014年12月06日
对于特性三. 多态和虚函数中举的例子,如果我们在Cat类中由于粗心,忘记了定义virtual const char* Speak() { return "Miao"; }
函数,那么函数的执行结果如下:
[jicanmeng@andy tmp]$ ./a.out
cCat is named Fred, and it says Miao
pAnimal is named Fred, and it says ???
rAnimal is named Fred, and it says ???
[jicanmeng@andy tmp]$
这显然不是我们想要的结果。为了避免这样的问题,我们需要仔细检查我们的代码,看我们是否忘记了Speak()函数。在程序量很大的时候,这种结果就很耗费时间。我们可以通过将Animal类中的Speak()函数声明为纯虚函数(pure virtual function),这样,在Cat类中必须要实现Speak()函数,否则程序会编译报错。让程序对自身进行检查,比我们进行检查可靠,而且大大节省时间。
程序代码如下:
#include <iostream> #include <string> class Animal { protected: std::string m_strName; // We're making this constructor protected because // we don't want people creating Animal objects directly, // but we still want derived classes to be able to use it. Animal(std::string strName) : m_strName(strName) { } public: std::string GetName() { return m_strName; } virtual const char* Speak() = 0; //pure virtual function }; class Cat: public Animal { public: Cat(std::string strName) : Animal(strName) { } virtual const char* Speak() { return "Miao"; } }; int main() { using namespace std; Cat cCat("Fred"); cout << "cCat is named " << cCat.GetName() << ", and it says " << cCat.Speak() << endl; Animal *pAnimal = &cCat; cout << "pAnimal is named " << pAnimal->GetName() << ", and it says " << pAnimal->Speak() << endl; Animal &rAnimal = cCat; cout << "rAnimal is named " << rAnimal.GetName() << ", and it says " << rAnimal.Speak() << endl; return 0; }
重点在第19行。Cat类继承了Animal类,必须要实现Animal类中定义的纯虚函数,否则使用Cat类实例化一个对象的时候,会编译报错(当然,如果不使用Cat类定义对象,就不会编译报错)。我们将30行注释掉再进行编译看一看:
[jicanmeng@andy tmp]$ g++ pure_function.cpp
pure_function.cpp: In function ‘int main()’:
pure_function.cpp:37: error: cannot declare variable ‘cCat’ to be of abstract type ‘Cat’
pure_function.cpp:23: note: because the following virtual functions are pure within ‘Cat’:
pure_function.cpp:19: note: virtual const char* Animal::Speak()
[jicanmeng@andy tmp]$
这就是纯虚函数的作用了:减少人为检查错误的时间,提高工作效率。
如果一个类包含纯虚函数,那么这个类就称为抽象类(abstract class)。C++中规定,不能使用抽象类实例化一个对象。如果一个类B继承了这个抽象类A,那么这个类B就必须要实现抽象类A中的纯虚函数,否则类B也是一个抽象类,也不能实例化对象。
如果一个类中不包含成员变量,只包含成员函数,而且这些成员函数全部都是纯虚函数,那么这样的类就称为接口类(interface class)。其实,接口类是抽象类的一种,不过比较特殊,所以单独列出来而已。
learncpp.com上面对interface class也有一些描述:
Interface classes have become extremely popular because they are easy to use, easy to extend, and easy to maintain. In fact, some modern languages, such as Java and C#, have added an “interface” keyword that allows programmers to directly define an interface class without having to explicitly mark all of the member functions as abstract. Furthermore, although Java and C# will not let you use multiple inheritance on normal classes, they will let you multiply inherit as many interfaces as you like. Because interfaces have no data and no function bodies, they avoid a lot of the traditional problems with multiple inheritance while still providing much of the flexibility.