原创
c++虚函数
2011-3-26 22:10
1313
6
6
分类:
工程师职场
二、虚函数的定义与派生类中的重定义
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再添加一个也是Size of A = 4
class A
{
public:
virtual void fun0()
{
cout << "A::fun0" << endl;
}
virtual void fun1()
{
cout << "A::fun1" << endl;
}
};
去掉virtual,Size of A = 1
class A
{
public:
void fun0()
{
cout << "A::fun0" << endl;
}
};
3
class A
{
public:
void fun0()
{
cout << "A::fun0" << endl;
}
int a;
int b;
};
Size of A = 8
其实虚函函数在内存中结构如下:
VPTR----&fun0
a-------
b-------
在windowxp下指针在内存中占4个字节,虚函数在一个虚函数表(VTABLE)中保存函数地址
4
VPTR->&fun0()
VPTR->&fun1()
VPTR->&funn()
5
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 of A = 12
VPTR->A
VPTR->B
VPTR->C
6
#include "iostream.h"
#include "string.h"
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;}
//delete and add
*/
};
int main(int argc, char* argv[])
{
A a;
B b;
C c;
Drive d;
a.f();
b.f();
c.f();
d.f();
return 0;
}
result:
A::f
B::f
C::f
C::f
7
用虚函数实现动态连接在编译期间,C++编译器根据程序传递给函数的参数或者函数返回类型来决定程序使用那个函数,然后编译器用正确的的函数替换每次启动。这种基于编译器的替换被称为静态连接,
他们在程序运行之前执行。另一方面,当程序执行多态性时,替换是在程序执行期进行的,这种运行期间替换被称为动态连接。
#include "iostream.h"
#include "string.h"
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;
cout<<"type B for class B,C for class C:"<<endl;
cin>>choice;
if(choice=='b')
test(b);
else if(choice=='c')
test(c);
cout<<endl<<endl;
return 0;
}
在上面的例子中,如果把类A,B,C中的virtual修饰符去掉,看看打印的结果,然后再看下面一个例子想想两者的联系。
如果把B和C中的virtual修饰符去掉,又会怎样,结果和没有去掉一样。
8
在基类中调用继承类的函数(如果此函数是虚函数才能如此)还是先看例子:
#include "iostream.h"
#include "string.h"
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
9
在上面例子中,test(A *a)其实有一个继承类指针向基类指针隐式转化的过程。可以看出利用虚函数我们可以在基类调用继承类函数。但如果不是虚函数,继承类指针转化为基类指针后只可以调用基类函数。
反之,如果基类指针向继承类指针转化的情况怎样,这只能进行显示转化,转化后的继承类指针可以调用基类和继承类指针。
#include "iostream.h"
#include "string.h"
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;
}
文章评论(0条评论)
登录后参与讨论