深入理解c++中virtual关键字
深入理解c++中virtual关键字
发布时间:2016-12-28 来源:查字典编辑
摘要:1.virtual关键字主要是什么作用?c++中的函数调用默认不适用动态绑定。要触发动态绑定,必须满足两个条件:第一,指定为虚函数;第二,通...

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;

}

输出为 Son call function

Father call function

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.虚函数的实现机制

关于虚函数的实现机制,我们以后在介绍。

10.小结

关于virtual关键字的用法总结如上,有错误或者总结不到位的情况请能帮本人指出!

11.例子

复制代码 代码如下:

class classA

{

public:

classA()

{

clear();

}

virtual ~classA()

{

}

void clear()

{

memset(this , 0 , sizeof(*this));

}

virtual void func()

{

printf("funcn");

}

};

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;

}

补充一个例子,这个程序输出依次是

func

func

出错

func

func

谈谈我的理解,当

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 class=cpp name="code">{</PRE><PRE class=cpp name="code"> classB()

{

clear();

}

virtual ~classB()

{

}

void clear()

{

memset(this , 0 , sizeof(*this));

}</PRE><BR>

<PRE></PRE>

<PRE class=cpp name="code">};</PRE>输出为

func

func

出错

出错

出错

推荐文章
猜你喜欢
附近的人在看
推荐阅读
拓展阅读
相关阅读
网友关注
最新C语言学习
热门C语言学习
编程开发子分类