C++中的虚函数(一)

转载 2012年03月29日 13:44:10

虽然很难找到一本不讨论多态性的C++书籍或杂志,但是,大多数这类讨论使多态性和C++虚函数的使用看起来很难。我打算在这篇文章中通过从几个方面和结合一些例子使读者理解在C++中的虚函数实现技术。说明一点,写这篇文章只是想和大家交流学习经验因为本人学识浅薄,难免有一些错误和不足,希望大家批评和指正,在此深表感谢!

一、 基本概念
首先,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 0;
}      
结果如下: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 0;
}      
结果如下: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 0;
}      
结果如下: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 0;
}
      
结果如下:结果如下:
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 0;
}      
结果如下:Size is = 12 ,相信大家一看下面的结构图就会很清楚,


图三

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 0;
}
结果:A::f
B::f
C::f
D::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(1);
	cout<<endl<<endl;
    return 0;
}
在上面的例子中,如果把类A,B,C中的virtual修饰符去掉,看看打印的结果,然后再看下面一个例子想想两者的联系。如果把B和C中的virtual修饰符去掉,又会怎样,结果和没有去掉一样。

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 0;
}      
打印结果:A::fun

在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<B *>(a); //基类指针向继承类指针进行显示转化
    pb->fun0();
	pb->fun();
	    return 0;
}  

什么是C++虚函数、虚函数的作用和使用方法

转自:http://c.biancheng.net/cpp/biancheng/view/244.html 我们知道,在同一类中是不能定义两个名字相同、参数个数和类型都相同的函数的,否则就是...
  • csCrazybing
  • csCrazybing
  • 2016年09月19日 12:53
  • 671

C++中虚函数的用法详细讲解

我们知道,在同一类中是不能定义两个名字相同、参数个数和类型都相同的函数的,否则就是“重复定义”。但是在类的继承层次结构中,在不同的层次中可以出现名字相同、参数个数和类型都相同而功能不同的函数。例如在例...
  • zhuaimiao1
  • zhuaimiao1
  • 2015年10月15日 22:43
  • 1651

C++ 虚函数 重载 重写的区别(转)

版权声明:本文转自http://blog.csdn.net/hackbuteer1/article/details/7475622  C++编程语言是一款应用广泛,支持多种程序设计的计算机编程语...
  • Primeprime
  • Primeprime
  • 2016年03月04日 00:29
  • 3839

C++中虚函数与纯虚函数以及虚继承的相关知识

这篇文章主要利用网上的博客,经过自己的总结写成,不免出现错误情况,如有错误,请指正。 虚函数 首先是虚函数的意义。在面向对象的设计思想中,虚函数的作用是实现多态性。如何实现多态呢?下面看C++虚函数表...
  • chy19911123
  • chy19911123
  • 2015年09月08日 20:42
  • 475

C++中虚函数的作用是什么?它应该怎么用呢?

虚函数联系到多态,多态联系到继承。所以本文中都是在继承层次上做文章。没了继承,什么都没得谈。下面是对C++的虚函数这玩意儿的理解。一, 什么是虚函数(如果不知道虚函数为何物,但有急切的想知道,那你就应...
  • weiyuefei
  • weiyuefei
  • 2016年04月12日 21:25
  • 898

关于C++中虚函数的作用

昨天去面试,面试官问道:虚函数有什么作用,我解释了半天也没解释清楚,其实说到底还是理解不够深刻,或者说简直没什么理解,连子类重写父类的普通函数和子类重写父类的虚函数的区别都不知道,真是弱爆了!!1 ...
  • qq792326645
  • qq792326645
  • 2015年11月21日 15:39
  • 1788

c++虚函数的使用方法

虚函数的使用方法: (1)在基类用virtual声明成员函数为虚函数。这样就可以在派生类中重新定义此函数,为它赋予新的功能,并能方便被调用。 在类外定义虚函数时,不必在定义virtual ...
  • tian_123456789
  • tian_123456789
  • 2016年05月08日 13:04
  • 7957

关于C++虚函数和纯虚函数

虚函数为了重载和多态的需要,在基类中是由定义的,即便定义是空,所以子类中可以重写也可以不写基类中的函数! 纯虚函数在基类中是没有定义的,必须在子类中加以实现,很像java中的接口函数! 虚...
  • pamchen
  • pamchen
  • 2013年03月06日 12:05
  • 1000

C++类的虚成员函数

一、简介 虚函数就是类的成员函数前面加上virtual关键字的函数。虚函数的作用就是为了实现多态性(Polymorphism),多态性是将接口与实现进行分离;用形象的语言来解释就是实现以共同...
  • peng_shakalaka
  • peng_shakalaka
  • 2017年04月19日 21:12
  • 463

C++虚继承虚基类虚函数纯虚函数总结

对于这些虚的,之前有很多歧义和不解,现在进行一下学习总结吧! 1.多重继承可能会导致二义性,而虚继承可以解决这个问题。虚继承是一种机制,类通过虚继承指出它希望共享其虚基类的状态,在虚继承下给定虚基类...
  • u011700461
  • u011700461
  • 2015年11月12日 16:59
  • 478
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:C++中的虚函数(一)
举报原因:
原因补充:

(最多只允许输入30个字)