c++ 中的virtual
1:virtual关键字主要有什么作用
c++中的函数调用默认不适用动态绑定,要触发动态绑定,必须满足两个条件:第一指定为虚函数; 第二通过基类类型的引用或指针调用。
2:哪些情况下可以使用virtual关键字呢
virtual可用来定义类函数和应用到虚继承中
注意:有元函数、构造函数、static静态函数不能用virtual关键字修饰。普通成员函数和析构函数可以用virtual关键字修饰。
举一个例子:
1 #include "stdafx.h" 2 #include<stdlib.h> 3 #include<iostream> 4 using namespace std; 5 6 class GrandFather 7 { 8 public: 9 GrandFather() {} 10 virtual void fun() 11 { 12 cout << "GrandFather call function" << endl; 13 } 14 }; 15 16 class Father:public GrandFather 17 { 18 public: 19 Father() {} 20 void fun() 21 { 22 cout << "Father call function"<< endl; 23 } 24 }; 25 26 class Son : public Father 27 { 28 public: 29 Son() {} 30 void fun() 31 { 32 cout << "Son call function" << endl; 33 } 34 }; 35 36 void Print( GrandFather* father ) 37 { 38 father->fun(); 39 } 40 41 int main(int argc, _TCHAR* argv[]) 42 { 43 Father* pfather = new Son; 44 pfather->fun(); 45 46 GrandFather* grandfather = new Father; 47 Print(grandfather); 48 49 return 0; 50 }
3:virtual的继承性
只要虚基类定义了virtual,继承类的该函数也就有virtual属性。
即GrandFather Father Son同时定义了virtual void fun() 与 GrandFather 一个定义virtual void fun效果是一样的。
4:虚析构函数
1 #include "stdafx.h" 2 #include<stdlib.h> 3 #include<iostream> 4 using namespace std; 5 6 class GrandFather 7 { 8 public: 9 GrandFather() {} 10 virtual void fun() 11 { 12 cout << "GrandFather call function" << endl; 13 } 14 ~GrandFather() 15 { 16 cout << "GrandFather dstruction " << endl; 17 } 18 }; 19 20 class Father:public GrandFather 21 { 22 public: 23 Father() {} 24 void fun() 25 { 26 cout << "Father call function"<< endl; 27 } 28 ~Father() 29 { 30 cout << " Father destruction " << endl; 31 } 32 }; 33 34 class Son : public Father 35 { 36 public: 37 Son() { cout << "son hello" << endl; } 38 void fun() 39 { 40 cout << "Son call function" << endl; 41 } 42 ~Son() 43 { 44 cout << " Son destruction " << endl; 45 } 46 }; 47 48 void Print( GrandFather* father ) 49 { 50 father->fun(); 51 } 52 53 int main(int argc, _TCHAR* argv[]) 54 { 55 //Father* pfather = new Son; 56 //pfather->fun(); 57 58 //GrandFather* grandfather = new Father; 59 //Print(grandfather); 60 61 Father* father = new Son; 62 delete father; 63 return 0; 64 }
运行结果为:
我们发现执行了Son的构造函数,没执行Son的析构函数,故把GrandFather的析构函数设置为virtual,如下例:
1 #include "stdafx.h" 2 #include<stdlib.h> 3 #include<iostream> 4 using namespace std; 5 6 class GrandFather 7 { 8 public: 9 GrandFather() {} 10 virtual void fun() 11 { 12 cout << "GrandFather call function" << endl; 13 } 14 virtual ~GrandFather() 15 { 16 cout << "GrandFather dstruction " << endl; 17 } 18 }; 19 20 class Father:public GrandFather 21 { 22 public: 23 Father() {} 24 void fun() 25 { 26 cout << "Father call function"<< endl; 27 } 28 ~Father() 29 { 30 cout << " Father destruction " << endl; 31 } 32 }; 33 34 class Son : public Father 35 { 36 public: 37 Son() { cout << "son hello" << endl; } 38 void fun() 39 { 40 cout << "Son call function" << endl; 41 } 42 ~Son() 43 { 44 cout << " Son destruction " << endl; 45 } 46 }; 47 48 void Print( GrandFather* father ) 49 { 50 father->fun(); 51 } 52 53 int main(int argc, _TCHAR* argv[]) 54 { 55 //Father* pfather = new Son; 56 //pfather->fun(); 57 58 //GrandFather* grandfather = new Father; 59 //Print(grandfather); 60 61 Father* father = new Son; 62 delete father; 63 return 0; 64 }
5:纯虚函数
纯虚函数的定义如下:
class CVirtual
{
public:
CVirtual() {}
virtual void fun() = 0
{
cout << " CVirtual call function " << endl;
}
virtual ~CVirtual()
{
cout << " CVirtual destruction " << endl;
}
};
纯虚函数为后代类提供可覆盖的接口,但这个类中的版本决不会调用。
含有(或继续)一个或多个纯虚函数的类是抽象基类,抽象基类不能实例化!
继承类只有重写这个接口才能被实例化.
这也许会让人联想到函数的重载,但是我们一比较就会发现两者是完全不同的。
1):重载的几个函数必须在同一个类中。而覆盖的函数必须在有继承关系的不同的类中。
2):覆盖的几个函数必须函数名、参数、返回值都相同。而重载的函数必须函数名相同,参数不同。参数不同的目的就是为了在函数调用的时候编译器能够通过参数来判断程序是在调用哪个函数。这也很自然的解释了为什么函数不能通过返回值类重载,因为程序在调用函数时很有可能不关心返回值的,编译器就无法从代码中看出程序在调用哪个函数了。
3):覆盖的函数前必须加关键字virtual;重载和virtual没有任何瓜葛,加不加都不影响重载的运作。