C++学习笔记——virtual学习

来源:互联网 发布:node.js addlistener 编辑:程序博客网 时间:2024/04/28 16:59

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~baseHere IN class son2,FUNC: print_m and its member=8~son2~baseHere 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~baseHere IN class son2,FUNC: print_m and its member=8~baseHere 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~baseIN Base: print_m;Line 13~son2~baseIN 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










0 0
原创粉丝点击