c++中虚函数
虽然很难找到一本不讨论多态性的C++书籍或杂志,但是,大多数这类讨论使多态性和C++虚函数的使用看起来很难。我打算在这篇文章中通过从几个方面和结合一些例子使读者理解在C++中的虚函数实现技术。说明一点,写这篇文章只是想和大家交流学习经验因为本人学识浅薄,难免有一些错误和不足,希望大家批评和指正,在此深表感谢!
在类中,如果什么都没有,则类占用1个字节,一旦类中有其他的占用空间成员,则这1个字节就不在计算之内,如一个类只有一个int则占用4字节而不是5字节。
如果只有成员函数,则还是只占用1个字节,因为类函数不占用空间
虚函数因为存在一个虚函数表,需要4个字节,数据成员对象如果为指针则为4字节,注意有字节对齐,如果为13字节,则进位到16字节空间。
一、 基本概念
首先,C++通过虚函数实现多态."无论发送消息的对象属于什么类,它们均发送具有同一形式的消息,对消息的处理方式可能随接手消息的对象而变"的处理方式被称为多态性。"在某个基类上建立起来的类的层次构造中,可以对任何一个派生类的对象中的同名过程进行调用,而被调用的过程提供的处理可以随其所属的类而变。"虚函数首先是一种成员函数,它可以在该类的派生类中被重新定义并被赋予另外一种处理功能。
二、 虚函数的定义与派生类中的重定义
class 类名{
public:
virtual 成员函数说明;
}
class 类名:基类名{
public:
virtual 成员函数说明;
}
三、 虚函数在内存中的结构
1.我们先看一个例子:
#include "iostream.h"
#include "string.h" class A {
public:
virtual void fun0() { cout << "A::fun0" << endl; }
}; int main(int argc, char* argv[])
{
A a;
cout << "Size of A = " << sizeof(a) << endl;
return ;
}
结果如下:Size of A = 4
2.如果再添加一个虚函数:virtual void fun1() { cout << "A::fun" << endl;}
得到相同的结果。如果去掉函数前面的virtual修饰符
class A {
public:
void fun0() { cout << "A::fun0" << endl; }
};
int main(int argc, char* argv[])
{
A a;
cout << "Size of A = " << sizeof(a) << endl;
return ;
}
结果如下:Size of A = 1
3.在看下面的结果:
class A {
public:
virtual void fun0() { cout << "A::fun0" << endl; }
int a;
int b;
};
int main(int argc, char* argv[])
{
A a;
cout << "Size of A = " << sizeof(a) << endl;
return ;
}
结果如下:Size of A = 12
其实虚函数在内存中结构是这样的:

图一
在window2000下指针在内存中占4个字节,虚函数在一个虚函数表(VTABLE)中保存函数地址。在看下面例子。
class A {
public:
virtual void fun0() { cout << "A::fun0" << endl; }
virtual void fun1() { cout << "A::fun1" << endl; }
int a;
int b;
};
int main(int argc, char* argv[])
{
A a;
cout << "Size of A = " << sizeof(a) << endl;
return ;
}
Size of A = 4
虚函数的内存结构如下,你也可以通过函数指针,先找到虚函数表(VTABLE),然后访问每个函数地址来验证这种结构,在国外网站作者是:Zeeshan Amjad写的"ATL on the Hood中有详细介绍"

图二
4.我们再来看看继承中虚函数的内存结构,先看下面的例子
class A {
public:
virtual void f() { }
};
class B {
public:
virtual void f() { }
};
class C {
public:
virtual void f() { }
};
class Drive : public A, public B, public C {
};
int main() {
Drive d;
cout << "Size is = " << sizeof(d) << endl;
return ;
}

图三
5.我们再来看看用虚函数实现多态性,先看个例子:
class A {
public:
virtual void f() { cout << "A::f" << endl; }
};
class B :public A{
public:
virtual void f() { cout << "B::f" << endl;}
};
class C :public A {
public:
virtual void f() { cout << "C::f" << endl;}
};
class Drive : public C {
public:
virtual void f() { cout << "D::f" << endl;}
};
int main(int argc, char* argv[])
{
A a;
B b;
C c;
Drive d;
a.f();
b.f();
c.f();
d.f();
return ;
}
结果:A::fB::fC::fD::f不用解释,相信大家一看就明白什么道理!注意:多态不是函数重载
6.用虚函数实现动态连接在编译期间,C++编译器根据程序传递给函数的参数或者函数返回类型来决定程序使用那个函数,然后编译器用正确的的函数替换每次启动。这种基于编译器的替换被称为静态连接,他们在程序运行之前执行。另一方面,当程序执行多态性时,替换是在程序执行期进行的,这种运行期间替换被称为动态连接。如下例子:
class A{
public:
virtual void f(){cout < < "A::f" < < endl;};
};
class B:public A{
public:
virtual void f(){cout < < "B::f" < < endl;};
};
class C:public A{
public:
virtual void f(){cout < < "C::f" < < endl;};
};
void test(A *a){
a->f();
};
int main(int argc, char* argv[])
{
B *b=new B;
C *c=new C;
char choice;
do{
cout< < "type B for class B,C for class C:"< < endl;
cin>>choice;
if(choice==''b'')
test(b);
else if(choice==''c'')
test(c);
}while();
cout< < endl< < endl;
return ;
}
7.在基类中调用继承类的函数(如果此函数是虚函数才能如此)
还是先看例子:
class A {
public:
virtual void fun() {
cout << "A::fun" << endl;
}
void show() {
fun();
}
};
class B : public A {
public:
virtual void fun() {
cout << "B::fun" << endl;
}
};
int main() {
A a;
a.show();
return ;
}
在6中的例子中,test(A *a)其实有一个继承类指针向基类指针隐式转化的过程。可以看出利用虚函数我们可以在基类调用继承类函数。但如果不是虚函数,继承类指针转化为基类指针后只可以调用基类函数。反之,如果基类指针向继承类指针转化的情况怎样,这只能进行显示转化,转化后的继承类指针可以调用基类和继承类指针。如下例子:
class A {
public:
void fun() {
cout << "A::fun" << endl;
}
};
class B : public A {
public:
void fun() {
cout << "B::fun" << endl;
}
void fun0() {
cout << "B::fun0" << endl;
}
};
int main() {
A *a=new A;
B *b=new B;
A *pa;
B *pb;
pb=static_cast(a); //基类指针向继承类指针进行显示转化
pb->fun0();
pb->fun();
return ;
}
1.科学出版社 《C++程序设计》
2.Zeeshan Amjad 《ATL on the Hood》
c++中虚函数的更多相关文章
- C++中虚函数的作用浅析
虚函数联系到多态,多态联系到继承.所以本文中都是在继承层次上做文章.没了继承,什么都没得谈. 下面是对C++的虚函数这玩意儿的理解. 一, 什么是虚函数(如果不知道虚函数为何物,但有急切的想知道,那你 ...
- 关于C++与Java中虚函数问题的读书笔记
之前一直用C++编程,对虚函数还是一些较为肤浅的理解.可近期由于某些原因搞了下Java,发现有些知识点不熟,于是站在先驱巨人的肩上谈谈C++与Java中虚函数问题. Java中的虚函数 以下是段别人的 ...
- C++中虚函数的作用是什么?它应该怎么用呢?(转)
虚函数联系到多态,多态联系到继承.所以本文中都是在继承层次上做文章.没了继承,什么都没得谈. 下面是对C++的虚函数这玩意儿的理解. 一, 什么是虚函数(如果不知道虚函数为何物,但有急切的想知道,那你 ...
- C++中虚函数功能的实现机制
要理解C++中虚函数是如何工作的,需要回答四个问题. 1. 什么是虚函数. 虚函数由于必须是在类中声明的函数,因此又称为虚方法.所有以virtual修饰符开始的成员函数都成为虚方法.此时注意是vir ...
- C++中虚函数的作用和虚函数的工作原理
1 C++中虚函数的作用和多态 虚函数: 实现类的多态性 关键字:虚函数:虚函数的作用:多态性:多态公有继承:动态联编 C++中的虚函数的作用主要是实现了多态的机制.基类定义虚函数,子类可以重写该函数 ...
- C++中虚函数实现原理揭秘
编译器到底做了什么实现的虚函数的晚绑定呢?我们来探个究竟. 编译器对每个包含虚函数的类创建一个表(称为V TA B L E).在V TA B L E中,编译器放置特定类的虚函 ...
- 【高级】C++中虚函数机制的实现原理
多态是C++中的一个重要特性,而虚函数却是实现多态的基石.所谓多态,就是基类的引用或者指针可以根据其实际指向的子类类型而表现出不同的功能.这篇文章讨论这种功能的实现原理,注意这里并不以某个具体的编译器 ...
- c++中虚函数和纯虚函数定义
只有用virtual声明类的成员函数,使之成为虚函数,不能将类外的普通函数声明为虚函数.因为虚函数的作用是允许在派生类中对基类的虚函数重新定义.所以虚函数只能用于类的继承层次结构中. 一个成员函数被声 ...
- C++ 在继承中虚函数、纯虚函数、普通函数,三者的区别
1.虚函数(impure virtual) C++的虚函数主要作用是“运行时多态”,父类中提供虚函数的实现,为子类提供默认的函数实现. 子类可以重写父类的虚函数实现子类的特殊化. 如下就是一个父类中的 ...
随机推荐
- Linux Home目录硬盘空间缩减
Linux Home目录硬盘空间缩减 操作 基于centos6.5 x86_64, runlevel 3,命令行模式,测试成功. 1.首先查看磁盘使用情况 [root@localhost ~]# ...
- 【selenium】下拉框和弹出框处理
#-*-coding=utf-8 from selenium import webdriver import os,time driver= webdriver.Firefox() driver.ge ...
- [转]Oracle中trace的几种
Oracle中trace的几种 标签: 杂谈 我们在Oracle中在做troubleshooting的时候,经常要去做跟踪来查错,那今天就介绍几种trace的方法. 在这之前,我先说说10046事 ...
- 关闭IE 对剪切板访问的提示
在internet 选项-“安全”选项卡-自定义级别. 在“脚本”下面找到“允许对剪切板进行编程访问”,选择“启用”即可. -END
- git 命令行 修改文件 并push(阿里云)
==============安装git后的准备https://code.aliyun.com/profile/keyshttps://code.aliyun.com/help/ssh/README = ...
- 【Hibernate学习笔记-5.2】使用@Temporal修饰日期类型的属性
作者:ssslinppp 1. 摘要 关于日期类型,Java和数据库表示的方法不同: Java:只有java.util.Date和java.util.Calender两种: 数据库:dat ...
- Spring 注解方式 实现 IOC 和 DI
注:以下所有测试案例(最后一个除外)的测试代码都是同一个: package cn.tedu.test; import org.junit.Test; import org.springframewor ...
- Logstash之一:入门介绍
简介 Logstash是一个接收,处理,转发日志的工具.支持系统日志,webserver日志,错误日志,应用日志,总之包括所有可以抛出来的日志类型.怎么样听起来挺厉害的吧?在一个典型的使用场景下(EL ...
- 开发框架-移动开发平台: mPaaS
ylbtech-开发框架-移动开发平台: mPaaS 移动开发平台 mPaaSmPaaS(Mobile PaaS)为 App 开发.测试.运营及运维提供云到端的一站式解决方案,能有效降低技术门槛.减少 ...
- [转]OBJECT_ID 有哪些种类
本文来自: http://www.cnblogs.com/biwork/archive/2013/01/07/2849311.html 特别是在建表建存储过程的时候进场会写到: IF OBJECT_I ...