给寻找编程代码教程的朋友们精选了c++相关的编程文章,网友关君浩根据主题投稿了本篇教程内容,涉及到virtual、virtual相关内容,已被136网友关注,相关难点技巧可以阅读下方的电子资料。
virtual
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; }
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; }
8. 构造函数和析构函数中的虚函数 如果在构造函数或析构函数中调用虚函数,则运行的是为构造函数或析构函数自身类型定义的版本
9.虚函数的实现机制 关于虚函数的实现机制,我们以后在介绍。
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 ob;的时候,注意memset的是classA的地址,所有ob的虚表是存在的
即是如下,通过指针或引用(动态绑定)访问oa的func函数(需要从虚表访问),会出错
访问ob的func和函数,无论静态访问还是动态访问,都不会出错
当把classB的代码改成如下时
class classB : public classA
<PRE style="FONT-WEIGHT: bold" class=cpp name="code">{</PRE><PRE style="FONT-WEIGHT: bold" class=cpp name="code"> classB() { clear(); } virtual ~classB() { } void clear() { memset(this , 0 , sizeof(*this)); }</PRE><BR> <PRE></PRE> <PRE style="FONT-WEIGHT: bold" class=cpp name="code">};</PRE>输出为