1.virtual关键字主要是什么作用?
c++中的函数调用默认不适用动态绑定。要触发动态绑定,必须满足两个条件:第一,指定为虚函数;第二,通过基类类型的引用或指针调用。 由此可见,virtual主要主要是实现动态绑定。2.那些情况下可以使用virtual关键字?
virtual可用来定义类函数和应用到虚继承。友元函数 构造函数 static静态函数 不能用virtual关键字修饰; 普通成员函数 和析构函数 可以用virtual关键字修饰;
3.virtual函数的效果
- class GrandFather
- {
- public:
- GrandFather() {}
- virtual void fun()
- {
- cout << "GrandFather call function!" << endl;
- }
- };
- class Father : public GrandFather
- {
- public:
- Father() {}
- void fun()
- {
- cout << "Father call function!" << endl;
- }
- };
- class Son : public Father
- {
- public:
- Son() {}
- void fun()
- {
- cout << "Son call function!" << endl;
- }
- };
- void print(GrandFather* father)
- {
- father->fun();
- }
- int _tmain(int argc, _TCHAR* argv[])
- {
- Father * pfather = new Son;
- pfather->fun();
- GrandFather * pgfather = new Father;
- print(pgfather);
- return 0;
- }
4.virtual的继承性
只要基函数定义了virtual,继承类的该函数也就具有virtual属性 即 GrandFather Father Son同时定义virtual void fun()与GrandFather一个定义virtual void fun效果是一样的5.虚析构函数
- class GrandFather
- {
- public:
- GrandFather() {}
- virtual void fun()
- {
- cout << "GrandFather call function!" << endl;
- }
- ~GrandFather()
- {
- cout << "GrandFather destruction!" << endl;
- }
- };
- class Father : public GrandFather
- {
- public:
- Father() {}
- void fun()
- {
- cout << "Father call function!" << endl;
- }
- ~Father()
- {
- cout << "Father destruction!" << endl;
- }
- };
- class Son : public Father
- {
- public:
- Son() {}
- void fun()
- {
- cout << "Son call function!" << endl;
- }
- ~Son()
- {
- cout << "Son destruction!" << endl;
- }
- };
- void print(GrandFather* p)
- {
- p->fun();
- }
- int _tmain(int argc, _TCHAR* argv[])
- {
- Father * pfather = new Son;
- delete pfather;
- return 0;
- }
以上代码输出:Father destruction! GrandFather destruction! 执行了Son的构造函数,没执行Son的析构函数,故把GrandFather的析构函数设置为virtual 则输出: Son destruction! Father Destruction! GrandFather destruction!
6. 纯虚函数
纯虚函数定义如下:- class GrandFather
- {
- public:
- GrandFather() {}
- virtual void fun() = 0
- {
- cout << "GrandFather call function!" << endl;
- }
- virtual ~GrandFather()
- {
- cout << "GrandFather destruction!" << endl;
- }
- };
纯虚函数为后代类提供可覆盖的接口,但这个类中的版本决不会调用。含有(或继续)一个或多个纯虚函数的类是抽象基类,抽象基类不能实例化!继承类只有重写这个接口才能被实例化
7.虚继承
虚继承主要解决交叉继承带来的问题。这里给出一片参考文章c++虚继承。给一个例子如下- class GrandFather
- {
- public:
- GrandFather() {}
- void fun()
- {
- cout << "GrandFather call function!" << endl;
- }
- virtual ~GrandFather()
- {
- cout << "GrandFather destruction!" << endl;
- }
- };
- class Father1 : public GrandFather
- {
- public:
- Father1() {}
- void fun()
- {
- cout << "Father call function!" << endl;
- }
- };
- class Father2 : public GrandFather
- {
- public:
- Father2() {}
- void fun()
- {
- cout << "Father call function!" << endl;
- }
- };
- class Son : public Father1, public Father2
- {
- public:
- Son() {}
- //void fun()
- //{
- // cout << "Son call function!" << endl;
- //}
- };
- void print(GrandFather* p)
- {
- p->fun();
- }
- int _tmain(int argc, _TCHAR* argv[])
- {
- Son* son = new Son;
- son->fun();
- return 0;
- }
编译时会提示报错对fun的访问不明确如果Father1和Father2都用虚继承继承GrandFather类则可以解决这个问题
8. 构造函数和析构函数中的虚函数
如果在构造函数或析构函数中调用虚函数,则运行的是为构造函数或析构函数自身类型定义的版本9.虚函数的实现机制关于虚函数的实现机制,这里给出一篇认为写得蛮清楚的文章。c++虚函数实现机制
10.小结
关于virtual关键字的用法总结如上,有错误或者总结不到位的情况请能帮本人指出!11.例子
- class classA
- {
- public:
- classA()
- {
- clear();
- }
- virtual ~classA()
- {
- }
- void clear()
- {
- memset(this , 0 , sizeof(*this));
- }
- virtual void func()
- {
- printf("func\n");
- }
- };
- class classB : public classA
- {
- };
- int main(void)
- {
- classA oa;
- classB ob;
- classA * pa0 = &oa;
- classA * pa1 = &ob;
- classB * pb = &ob;
- oa.func(); // 1
- ob.func(); // 2
- pa0->func(); // 3
- pa1->func(); // 4
- pb->func(); // 5
- return 0;
- }
谈谈我的理解,当classA oa;oa.func();不存在动态调用的过程,所以func虽然是虚函数,但是函数调用不通过虚表访问,所以即使
- memset(this , 0 , sizeof(*this));
当把classB的代码改成如下时
- class classB : public classA
- <pre name="code" class="cpp" style="font-weight: bold;">{</pre><pre name="code" class="cpp" style="font-weight: bold;"> classB()
- {
- clear();
- }
- virtual ~classB()
- {
- }
- void clear()
- {
- memset(this , 0 , sizeof(*this));
- }</pre><br>
- <pre></pre>
- <pre name="code" class="cpp" style="font-weight: bold;">};</pre>输出为