intmain(){Basebase;// We can't instantiate an abstract base class, but for the sake of example, pretend this was allowedbase.getValue();// what would this do?return0;}
#include<string>classAnimal{protected:std::stringm_name;// 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(conststd::string&name):m_name{name}{}public:std::stringgetName()const{returnm_name;}virtualconstchar*speak()const{return"???";}virtual~Animal()=default;//默认析构函数(虚函数)};classCat:publicAnimal{public:Cat(conststd::string&name):Animal{name}{}constchar*speak()constoverride{return"Meow";}};classDog:publicAnimal{public:Dog(conststd::string&name):Animal{name}{}constchar*speak()constoverride{return"Woof";}};
#include<iostream>classCow:publicAnimal{public:Cow(conststd::string&name):Animal{name}{}// We forgot to redefine speak};intmain(){Cowcow{"Betsy"};std::cout<<cow.getName()<<" says "<<cow.speak()<<'\n';return0;}
(33): error C2259: 'Cow': cannot instantiate abstract class
(20): note: see declaration of 'Cow'(33): note: due to following members:
(33): note: 'const char *Animal::speak(void) const': is abstract
(15): note: see declaration of 'Animal::speak'
#include<iostream>#include<string>classAnimal// This Animal is an abstract base class{protected:std::stringm_name;public:Animal(conststd::string&name):m_name{name}{}conststd::string&getName()const{returnm_name;}virtualconstchar*speak()const=0;// note that speak is now a pure virtual functionvirtual~Animal()=default;};classCow:publicAnimal{public:Cow(conststd::string&name):Animal(name){}constchar*speak()constoverride{return"Moo";}};intmain(){Cowcow{"Betsy"};std::cout<<cow.getName()<<" says "<<cow.speak()<<'\n';return0;}
intmain(){Cowcow{"Betsy"};Animal&a{cow};std::cout<<a.speak();// resolves to Cow::speak(), prints "Moo"return0;}
在上面的例子中,a.speak() 通过虚函数解析解析为 Cow::speak() 。
由于带有纯虚函数的类具有虚函数,所以不要忘记将析构函数也设置为虚函数。
有函数体(定义)的纯虚函数
事实证明我们可以创建具有函数体的纯虚函数:
1 2 3 4 5 6 7 8 91011121314151617181920212223
#include<string>classAnimal// This Animal is an abstract base class{protected:std::stringm_name;public:Animal(conststd::string&name):m_name{name}{}std::stringgetName(){returnm_name;}virtualconstchar*speak()const=0;// = 0 意味着这是纯虚函数virtual~Animal()=default;};constchar*Animal::speak()const// 即使该函数有定义{return"buzz";}
classIErrorLog{public:virtualboolopenLog(constchar*filename)=0;virtualboolcloseLog()=0;virtualboolwriteError(constchar*errorMessage)=0;virtual~IErrorLog(){}// make a virtual destructor in case we delete an IErrorLog pointer, so the proper derived destructor is called};
#include<cmath> // for sqrt()doublemySqrt(doublevalue,FileErrorLog&log)//注意参数使用的是FileErrorLog类型{if(value<0.0){log.writeError("Tried to take square root of value less than 0");return0.0;}else{returnstd::sqrt(value);}}
更加灵活的办法是将该函数实现为使用 IErrorLog 类型的参数:
1 2 3 4 5 6 7 8 910111213
#include<cmath> // for sqrt()doublemySqrt(doublevalue,IErrorLog&log){if(value<0.0){log.writeError("Tried to take square root of value less than 0");return0.0;}else{returnstd::sqrt(value);}}