C++学习笔记——virtual学习
2014-05-11 17:05
405 查看
1、含义
virtual关键字只用于类定义内部,出了类定义范围无法使用,即只能用于限定成员函数定义为virtual的函数是基类希望派生类重新定义的,否则不能声明为virtual函数。
C++中的类成员函数默认为非virtual函数。
2、virtual与动态绑定
通过动态绑定我们能够在编写程序时使用继承层次中的任意对象,无需关心对象的具体类型。使用这些类的程序无需关心函数是在基类还是在派生类中定义。在C++中通过基类的引用(或指针)调用虚函数时候,发生动态绑定,即引用(或指针)既可以是指向基类对象也可以是指向派生类对象。用引用(或指针)调用的虚函数在运行时确定被调用函数的实际定义。
触发条件:
只有指定为虚函数的成员函数才能进行动态绑定;
必须通过基类类型的引用或指针进行函数调用;
3、virtual与派生类
派生类一般会重新定义所有基类的虚函数(继承的),如果没有重新定义虚函数则默认使用基类中版本。派生类中对于虚函数的声明必须与基类中完全一样(但若返回类型是对基类的引用或指针的虚函数,在派生类中可以返回基类函数所返回类型的派生类应用或指针)。
一旦函数在基类中声明为虚函数,它就一直为虚函数,派生类可以保留virtual关键字。
4、virtual与构造、析构函数
C++明确指出:当派生类对象通过基类指针被删除,而该基类有non-virtual析构函数,其结果未定义——实际执行时候该派生类的派生成分未被销毁,只销毁了继承自基类的部分。这就发生了诡异的“局部销毁”,形成资源泄露。因此:任何有多态性或者含有virtual函数的基类都必须包含有一个virtual析构函数。此外决不能在构造函数和析构函数中调用virtual函数,具体原因见参考文献【1】。
5、virtual与强制覆盖
某些情况下希望覆盖虚函数,强调使用虚函数的特定版本,这是可以使用作用域操作符:base *p_base = &dreived;
T d = p_base->base_class::print_m();
这段代码强调对于func()的调用确定为base中定义的版本,这就使该调用在编译是确定。
6、pure virtual
如果某个基类只是为了让其他类继承而不会有或者不应该有类对象,可以在类中定义纯虚函数(pure virtual function)。包含纯虚函数的类为抽象类,抽象类除了作为抽象基类进行派生,抽象类不能创建对象。class base { public: virtual void print_m() = 0; }
上面定义的base为抽象类,func为纯虚函数。
7、示例
#include <iostream> #include <vector> #include <boost/foreach.hpp> using namespace std; class base { public: virtual ~base(){ cout<<__func__<<"\n"; } virtual void print_m(){ cout<<"IN Base: "<<__func__<<";Line "<<__LINE__<<"\n"; } }; //======================================================================= class son1 : public base { public: son1(int mem):member(mem){ } ~son1() { cout<<__func__<<"\n"; } void print_m() { cout<<"Here IN class son1,FUNC: "<<__func__<<" and its member="<<member<<"\n"; } private: int member; }; //======================================================================= class son2 : public base { public: son2(int mem):member(mem){ } ~son2() { cout<<__func__<<"\n"; } void print_m() { cout<<"Here IN class son2,FUNC: "<<__func__<<" and its member="<<member<<"\n"; } private: int member; }; //======================================================================= class son3 : public base { public: son3(int mem):member(mem){ } ~son3() { cout<<__func__<<"\n"; } void print_m() { cout<<"Here IN class son3,FUNC: "<<__func__<<" and its member="<<member<<"\n"; } private: int member; }; //======================================================================= base * get_base_ptr(int i, int mem=6) { switch (i) { case 1 : return new son1(mem); case 2 : return new son2(mem); default : return new son3(mem); } } int main() { std::vector<base*> v; for (int i = 1; i <= 3; ++i) { v.push_back(get_base_ptr(i,i*i*i)); } BOOST_FOREACH(base * &b,v) { b->print_m(); if(b!=NULL) delete b; } return 0; } /*****************执行结果************************* Here IN class son1,FUNC: print_m and its member=1 ~son1 ~base Here IN class son2,FUNC: print_m and its member=8 ~son2 ~base Here IN class son3,FUNC: print_m and its member=27 ~son3 ~base [Finished in 0.6s] **************************************************/并且如果去掉基类中析构函数的virtual输出结果为:
/*****************执行结果************************* Here IN class son1,FUNC: print_m and its member=1 ~base Here IN class son2,FUNC: print_m and its member=8 ~base Here IN class son3,FUNC: print_m and its member=27 ~base [Finished in 0.6s] **************************************************/可以看出如果没有基类的虚析构函数,在通过基类指针销毁派生类对象时候未能完全销毁。
此时基类为抽象类,如果给该基类声明对象
base b;则会出现以下错误:
/home/abing/software/clang_tool/test.cc: 在函数‘int main()’中: /home/abing/software/clang_tool/test.cc:74:10: 错误: 不能将变量‘b’声明为具有抽象类型‘base’ /home/abing/software/clang_tool/test.cc:6:7: 附注: 因为下列虚函数在‘base’中为纯虚函数: /home/abing/software/clang_tool/test.cc:15:18: 附注: virtual void base::print_m() [Finished in 0.4s with exit code 1]
如果将基类中的:
virtual void print_m() = 0 ;
改为:
virtual void print_m(){ cout<<"IN Base: "<<__func__<<";Line "<<__LINE__<<"\n"; }并且将
BOOST_FOREACH(base * &b,v) { b->print_m(); if(b!=NULL) delete b; }改为:
BOOST_FOREACH(base * &b,v) { b->base::print_m(); if(b!=NULL) delete b; }则执行结果为:
/*****************执行结果************************* IN Base: print_m;Line 13 ~son1 ~base IN Base: print_m;Line 13 ~son2 ~base IN Base: print_m;Line 13 ~son3 ~base [Finished in 0.6s] **************************************************/8、参考文献
[1] 《C++ Primer》第四版
[2] 《Effective C++》第三版
注:转载请说明出处http://blog.csdn.net/abingzhao/article/details/25548263
相关文章推荐
- C++ 调用C函数
- c++11 中auto 相当方便
- 顺序栈的c语言实现(程序可运行)。。。2014.5.11
- C语言的BSS段问题
- C语言笔记——32个关键字
- c++ 中private继承
- 移植C/C++代码的十个技巧
- 3. 字符型
- C++中new和malloc的区别
- 2. 浮点型
- 1. 整型
- C语言实现C++的继承和多态
- 【转载】如何使用Visual Studio 2010(VS2010)编译C语言
- 学习C/C++语言:递归求解hanoi汉诺塔问题
- 【转载】使用 VC++ 6.0 的一些提示
- 2. scanf的用法
- c++绘图软件<一>
- C++初学者
- C++将数字转为字符串,并拼接
- 1. printf 的用法