最常见的用法就是声明基类的指针,利用该指针指向任意一个子类对象,调用相应的虚函数,可以根据指向的子类的不同而实现不同的方法。如果没有使用虚函数的话,即没有利用C++多态性,则利用基类指针调用相应的函数的时候,将总被限制在基类函数本身,而无法调用到子类中被重写过的函数。因为没有多态性,函数调用的地址将是一定的,而固定的地址将始终调用到同一个函数,这就无法实现一个接口,多种方法的目的了。
C++纯虚函数
一、定义
纯虚函数是在基类中声明的虚函数,它在基类中没有定义,但要求任何派生类都要定义自己的实现方法。在基类中实现纯虚函数的方法是在函数原型后加“=0”
virtual void funtion()=0
二、引入原因
1、为了方便使用多态特性,我们常常需要在基类中定义虚拟函数。
2、在很多情况下,基类本身生成对象是不合情理的。例如,动物作为一个基类可以派生出老虎、孔雀等子类,但动物本身生成对象明显不合常理。
为了解决上述问题,引入了纯虚函数的概念,将函数定义为纯虚函数(方法:virtual ReturnType Function()= 0;),则编译器要求在派生类中必须予以重写以实现多态性。同时含有纯虚拟函数的类称为抽象类,它不能生成对象。这样就很好地解决了上述两个问题。
三、相似概念
1、多态性
指相同对象收到不同消息或不同对象收到相同消息时产生不同的实现动作。C++支持两种多态性:编译时多态性,运行时多态性。
a、编译时多态性:通过重载函数实现 b、运行时多态性:通过虚函数实现。
2、虚函数
虚函数是在基类中被声明为virtual,并在派生类中重新定义的成员函数,可实现成员函数的动态覆盖(Override)
3、抽象类
包含纯虚函数的类称为抽象类。由于抽象类包含了没有定义的纯虚函数,所以不能定义抽象类的对象
/*纯虚函数--规定了对外接口的统一形式,作为基类来使用*/ #include <iostream> using namespace std; class Base1{ public: virtual void display() const = 0;//纯虚函数,0表示没有函数体 }; class Base2: public Base1{ //公有派生类的定义 public: virtual void display() const; //覆盖基类的虚函数 }; void Base2::display() const{ cout << "Base2::display()" << endl; } class Derived: public Base2{ //公有派生类的定义 public: virtual void display() const; //覆盖基类的虚函数 }; void Derived::display() const{ cout << "Derived::display()" << endl; } void fun(Base1 *ptr){ ptr->display(); } int main(){ Base2 base2; Derived derived; fun(&base2); fun(&derived); return 0; }
/*单目运算符"++"重载为成员函数对形式*/ /*语法规定:前置的单目运算符重载为成员函数时没有形参,而后置单目运算符重载为成员函数时需要有一个int型形参*/ #include <iostream> using namespace std; class Clock{ public: Clock(int hour = 0, int minute = 0, int second = 0); void showTime() const; Clock& operator++();//前置单目运算符重载 Clock operator++(int);//后置单目运算符重载 private: int hour, minute, second; }; Clock::Clock(int hour, int minute, int second){ if(hour>=0 && hour<24 && minute>=0 && minute<60 && second>=0 && second<60 ){ this->hour = hour; this->minute = minute; this->second = second; } else cout << "Time error!" << endl; } void Clock::showTime() const{ cout << hour << ":" << minute << ":" << second << endl; } Clock& Clock::operator++(){//前置单目运算符重载函数 second++; if(second >= 60){ second -= 60; minute++; if(minute >= 60){ minute -= 60; hour = (hour+1)%24; } } return *this; } Clock Clock::operator++(int){//后置单目运算符重载,注意参数表中有整型参数,int用于区分是前置还是后置,无实质性作用。 Clock old = *this; ++(*this); return old; } int main(){ Clock myClock(23, 59, 59); cout << "Fist time output: "; myClock.showTime(); cout << "Show myClock++: "; (myClock++).showTime();//先用再加1 cout << "Show ++myClock: "; (++myClock).showTime(); //先加1再用 return 0; }
/*加减运算符的重载*/ #include <iostream> using namespace std; class Complex{ public: Complex(double r = 0.0, double i = 0.0): real(r), imag(i){}//构造函数 Complex operator+(const Complex &c2) const;//运算符+重载成员函数 Complex operator-(const Complex &c2) const;//运算符-重载成员函数 void display() const; private: double real; double imag; }; Complex Complex::operator+(const Complex &c2) const{//重载运算符实现 return Complex(real + c2.real, imag + c2.imag);//创建一个临时无名的对象作为返回值 } Complex Complex::operator-(const Complex &c2) const{//重载运算符实现 return Complex(real - c2.real, imag - c2.imag);//创建一个临时无名的对象作为返回值 } void Complex::display() const{ cout << "(" << real << "," << imag << ")" << endl; } int main(){ Complex c1(5, 4), c2(2, 10), c3; cout << "c1 = "; c1.display(); cout << "c2 = "; c2.display(); c3 = c1 - c2; cout << "c3 = c1 - c2 = "; c3.display(); c3 = c1 + c2; cout << "c3 = c1 + c2 = "; c3.display(); return 0; }
/*虚函数实现运行的多态*/ #include <iostream> using namespace std; class Base1{ public: virtual void display() const;//声明为虚函数后,都要在类外实现函数,不能写成内联函数,它不会在编译阶段调用display,而再运行时调用 }; void Base1::display() const{ cout << "Base1::display()" << endl; } class Base2: public Base1 { //公有派生类的Base2的定义 public: virtual void display() const;//覆盖基类的虚函数 ,派生类可以不显式的用virtual声明虚函数,故派生类的virtual可以省略 }; void Base2::display() const{ cout << "Base2::display()" << endl; } class Derived: public Base2{ public: virtual void display() const;//覆盖基类的虚函数 }; void Derived::display() const{ cout << "Derived::display()" << endl; } void fun(Base1 *ptr){ ptr->display(); } int main(){ Base1 base1; Base2 base2; Derived derived; fun(&base1); fun(&base2); fun(&derived); return 0; }
/*虚析构函数*/ #include <iostream> using namespace std; class Base{ public: virtual ~Base(); }; Base::~Base(){ cout << "Base destructor" << endl; } class Derived:public Base{ public: Derived(); ~Derived(); private: int *p; }; Derived::Derived(){ p = new int(0); } Derived::~Derived(){ cout << "Derived destructor" << endl; delete p; } void fun(Base *b){ delete b; } int main(){ Base *b = new Derived(); fun(b); return 0; }
/*运算符重载为非成员函数--必须把操作数全部通过形参的方式传递给运算符重载函数*/ #include <iostream> using namespace std; class Complex{ public: Complex(double r = 0.0, double i = 0.0): real(r), imag(i){}//构造函数 //将下面的函数声明为友元函数,以便重载为非成员函数后在外部可以调用类的私有成员 friend Complex operator+(const Complex &c1, const Complex &c2);//运算符+重载成员函数 friend Complex operator-(const Complex &c1, const Complex &c2);//运算符-重载成员函数 friend ostream & operator<<(ostream &out, const Complex &c);//重载插入运算符<< void display() const; private: double real; double imag; }; //下面的函数已经重载为类外的全局函数,故不用Complex Complex::operator+ Complex operator+(const Complex &c1, const Complex &c2){//重载运算符实现 return Complex(c1.real + c2.real, c1.imag + c2.imag);//创建一个临时无名的对象作为返回值 } Complex operator-(const Complex &c1, const Complex &c2){//重载运算符实现 return Complex(c1.real - c2.real, c1.imag - c2.imag);//创建一个临时无名的对象作为返回值 } ostream & operator<<(ostream &out, const Complex &c){ out <<"(" << c.real << "," << c.imag << ")"; return out; } void Complex::display() const{ cout << "(" << real << "," << imag << ")" << endl; } int main(){ Complex c1(5, 4), c2(2, 10), c3; cout << "c1 = "; c1.display(); cout << "c2 = "; c2.display(); c3 = c1 - c2; cout << "c3 = c1 - c2 = "; c3.display(); c3 = c1 + c2; cout << "c3 = c1 + c2 = "; c3.display(); return 0; }