c++ 中多态总结以及虚表剖析

1.对象类型

 

 

 

 

 

 

 

class B
{};
class D:public B
{};
void FunTest()
{
 D* d;//d的静态类型为D*
    B* b = d;//b的静态类型为B*,动态类型为D*
}

多态性是面向对象程序设计的一个重要特征,利用多态性可以设计和实现一个易于扩展的系统。那么何为多态呢?多态就是向不同的对象发送同一个消息,不同的对象在接收时会产生不同的行为(方法);

例如:使用运算符“+”使两个数值相加,就是发送一个消息,他要调用operator+函数,实际上,整型,单精度型,双精度型的加法操作过程是互相不同的,是由不同内容的函数实现的。很明显,它们是通过不同的方法来响应同一消息。

C++中,多态的表现形式之一是:具有不同功能的函数可以用同一个函数名,这样就可以实现用一个函数名调用不同内容的函数。总而言之,多态就是“一个接口,多种方法”。

多态也分为两类:

 

 

 实现多态的条件:

1:派生类重写基类虚函数

2:通过基类指针或引用调用基类虚函数(该虚函数在派生类中必须被重写)

代码如下:

class B
{
public:
virtual void fun()
{
cout<<"B::fun()"<<endl;
}
int _data;
};
class D:public B
{
public:
virtual void fun()//在派生类中重写基类的虚函数
{
cout<<"D::fun()"<<endl;
}
int _data1;
};
void FunTest()
{
B* b;
D d;
b =&d;
b->fun();//通过基类的指针或引用调用虚函数
}

 

 

 

*重写、重定义、重载的区别

重载:作用域相同,函数名相同,参数列表不同,返回值类型可以不同;

重定义(隐藏):作用域不同(分别位于基类和派生类中),函数名相同,派生类隐藏基类,      访问修饰符可以不同;

重写(覆盖):作用域不同(分别位于基类和派生类中),函数名相同,必须是虚函数,参数列表相同,返回值类型相同(协变除外)

协变:函数值返回值类型不同,基类的函数返回值类型为基类的引用,派生类的函数返回值类型为派生类的引用。

 

纯虚函数:在虚函数后+= 0 ”就构成了纯虚函数,包含纯虚函数的类叫做抽象类(接口);

 

virtual void  Test() = 0;

说明: static成员函数、构造函数、 拷贝构造函数、友元函数(不是类中的成员函数)等函数不能作为虚函数。析构函数可以作为虚函数,赋值运算符重载虽然可以作为虚函数,但是它属于协变,不推荐使用

*协变:函数返回值不同,基类返回基类的对象的引用,派生类返回派生类的对象的引用。

 

 

虚表:对于每一个含有虚函数的类,编译器都会维护一张虚表,对象的前四个字节就是指向虚表的指针。

class B
{
public:
virtual void test()
{
cout<<"B::test()"<<endl;
}
int _data;
};
int main()
{
B b;
b._data = 1;
system("pause");
return 0;
}
 

 

说明:

    1)同一个类中不同对象,共用同一张虚表;


     2)虚表在构造函数的初始化列表时处理

  

     3)虚表的创建:派生类中未重写虚函数时直接拷贝基类的虚表,若重写了则用被重写的虚函数去替换原来的虚函数

      无覆盖:

 

class Base
{
public:
virtual void Test1()
{
cout<<"Base::Test1()"<<endl;
}
virtual void Test2()
{
cout<<"Base::Test()2"<<endl;
}
virtual void Test3()
{
cout<<"Base::Test3()"<<endl;
}
int _data1;
};
class Derived:public Base
{
public:
virtual void Test4()
{
cout<<"Derived::Test4()"<<endl;
}
virtual void Test5()
{
cout<<"Derived::Test5()"<<endl;
}
virtual void Test6()
{
cout<<"Derived::Test6()"<<endl;
}
int _data2;
};
typedef void(*VFP)();
void PrintVfp()
{
Base b;
VFP* vfp = (VFP*)*(int *)&b;
cout<<"Base vir table:"<<endl;
while(*vfp)
{
(*vfp)();
++vfp;
}
cout<<endl;
Derived d;
VFP* vfp1 = (VFP*)*(int *)&d;
cout<<"Derived vir table:"<<endl;
while(*vfp1)
{
(*vfp1)();
++vfp1;
}
cout<<endl;
}

 

 

有覆盖:

class Base
{
public:
virtual void Test1()
{
cout<<"Base::Test1()"<<endl;
}
virtual void Test2()
{
cout<<"Base::Test2()"<<endl;
}
virtual void Test3()
{
cout<<"Base::Test3()"<<endl;
}
virtual void Test4()
{
cout<<"Base::Test4()"<<endl;
}
int _data1;
};
class Derived:public Base
{
public:
virtual void Test3()
{
cout<<"Derived::Test3()"<<endl;
}
virtual void Test4()
{
cout<<"Derived::Test4()"<<endl;
}
virtual void Test5()
{
cout<<"Derived::Test5()"<<endl;
}
virtual void Test6()
{
cout<<"Derived::Test6()"<<endl;
}
int _data2;
};
typedef void(*VFP)();
void PrintVfp()
{
Base b;
VFP* vfp = (VFP*)*(int *)&b;
cout<<"Base vir table:"<<endl;
while(*vfp)
{
(*vfp)();
++vfp;
}
cout<<endl;
Derived d;
VFP* vfp1 = (VFP*)*(int *)&d;
cout<<"Derived vir table:"<<endl;
while(*vfp1)
{
(*vfp1)();
++vfp1;
}
cout<<endl;
}

 

 

 

 

 

多重继承无覆盖


 
class Base1
{
public:
Base1()
:_data1(1)
{}
virtual void Test1()
{
cout<<"Base::Test1()"<<endl;
}
virtual void Test2()
{
cout<<"Base::Test()2"<<endl;
}
virtual void Test3()
{
cout<<"Base::Test3()"<<endl;
}
int _data1;
};
class Base2
{
public:
Base2()
:_data2(2)
{}
virtual void Test4()
{
cout<<"Base::Test4()"<<endl;
}
virtual void Test5()
{
cout<<"Base::Test()5"<<endl;
}
virtual void Test6()
{
cout<<"Base::Test6()"<<endl;
}
int _data2;
};
class Derived:public Base1,public Base2
{
 
public:
Derived()
:_data3(3)
{}
virtual void Test7()
{
cout<<"Derived::Test7()"<<endl;
}
int _data3 ;
};
typedef void(*VFP)();
void PrintVfp()
{
Derived d;
Base1& b1 = d;
VFP* vfp1 = (VFP*)*(int *)&b1;
cout<<"Base1 vir table:"<<endl;
while(*vfp1)
{
(*vfp1)();
++vfp1;
}
cout<<endl;
Base2& b2 = d;
VFP* vfp2 = (VFP*)*(int *)&b2;
cout<<"Base2 vir table:"<<endl;
while(*vfp2)
{
(*vfp2)();
++vfp2;
}
cout<<endl;
VFP* vfp3 = (VFP*)*(int *)&d;
cout<<"D vir table:"<<endl;
while(*vfp3)
{
(*vfp3)();
++vfp3;
}
cout<<endl;
}

多重继承有覆盖:
class Base1
{
public:
Base1()
:_data1(1)
{}
virtual void Test1()
{
cout<<"Base::Test1()"<<endl;
}
virtual void Test2()
{
cout<<"Base::Test()2"<<endl;
}
virtual void Test3()
{
cout<<"Base::Test3()"<<endl;
}
int _data1;
};
class Base2
{
public:
Base2()
:_data2(2)
{}
virtual void Test4()
{
cout<<"Base::Test4()"<<endl;
}
virtual void Test5()
{
cout<<"Base::Test()5"<<endl;
}
virtual void Test6()
{
cout<<"Base::Test6()"<<endl;
}
int _data2;
};
class Derived:public Base1,public Base2
{
 
public:
Derived()
:_data3(3)
{}
virtual void Test1()
{
cout<<"Derived::Test1()"<<endl;
}
virtual void Test5()
{
cout<<"Derived::Test5()"<<endl;
}
virtual void Test7()
{
cout<<"Derived::Test7()"<<endl;
}
int _data3 ;
};
typedef void(*VFP)();
void PrintVfp()
{
Derived d;
Base1& b1 = d;
VFP* vfp1 = (VFP*)*(int *)&b1;
cout<<"Base1 vir table:"<<endl;
while(*vfp1)
{
(*vfp1)();
++vfp1;
}
cout<<endl;
Base2& b2 = d;
VFP* vfp2 = (VFP*)*(int *)&b2;
cout<<"Base2 vir table:"<<endl;
while(*vfp2)
{
(*vfp2)();
++vfp2;
}
cout<<endl;
VFP* vfp3 = (VFP*)*(int *)&d;
cout<<"D vir table:"<<endl;
while(*vfp3)
{
(*vfp3)();
++vfp3;
}
cout<<endl;
}
 

 

菱形继承:

class Base
{
public:
Base()
:_data1(0)
{}
virtual void Test1()
{
cout<<"Base::Test1()"<<endl;
}
int _data1;
};
class C1:public Base
{
public:
virtual void Test1()
{
cout<<"C1::Test1()"<<endl;
}
virtual void Test2()
{
cout<<"C1::Test2()"<<endl;
}
int _data2;
};
class C2:public Base
{
public:
virtual void Test1()
{
cout<<"C2::Test1()"<<endl;
}
virtual void Test3()
{
cout<<"C2::Test3()"<<endl;
}
int _data3;
};
class D:public C1,public C2
{
public:
virtual void Test1()
{
cout<<"D::Test1()"<<endl;
}
virtual void Test2()
{
cout<<"D::Test2()"<<endl;
}
virtual void Test3()
{
cout<<"D::Test3()"<<endl;
}
virtual void Test4()
{
cout<<"D::Test4()"<<endl;
}
int _data4;
};
typedef void(*VFP)();
void PrintVfp()
{
D d;
C1& c1 = d;
VFP* vfp1 = (VFP*)*(int *)&c1;
cout<<"C1 vir table:"<<endl;
while(*vfp1)
{
(*vfp1)();
++vfp1;
}
cout<<endl;
C2& c2 = d;
VFP* vfp2 = (VFP*)*(int *)&c2;
cout<<"C2 vir table:"<<endl;
while(*vfp2)
{
(*vfp2)();
++vfp2;
}
cout<<endl;
}
int main()
{
PrintVfp();
D d;
d.C1::_data1 = 0;
d.C2::_data1 = 1;
d._data2 = 2;
d._data3 = 3;
d._data4 = 4;
system("pause");
return 0;
}

 

 

虚继承:
class B
{
public:
virtual void fun1()
{
cout<<"B::fun1()"<<endl;
}
virtual void fun2()
{
cout<<"B::fun2()"<<endl;
}
int _data1;
};
class D :virtual public B
{
public:
D()
{}
~D()
{}
virtual void fun2()
{
cout<<"D::fun1()"<<endl;
}
virtual void fun3()
{
cout<<"D::fun3()"<<endl;
}
int _data2;
};
typedef void(*VFP)();
void PrintVfp()
{
D d;
VFP* vfp1 = (VFP*)*(int *)&d;
cout<<"D vir table up:"<<endl;
while(*vfp1)
{
(*vfp1)();
++vfp1;
}
cout<<endl;
B& b = d;
VFP* vfp2 = (VFP*)*(int *)&b;
cout<<"D vir table down:"<<endl;
while(*vfp2)
{
(*vfp2)();
++vfp2;
}
cout<<endl;
}
void FunTest()
{
cout<<sizeof(D)<<endl;//24,但是去掉构造函数和析构函数大小-4
D d;
d._data1 = 1;
d._data2 = 2;
 
}

 

 

说明:若派生类中没有新的虚函数,在虚表中没有派生类的虚表指针


*没有构造函数,类大小-4,那么构造函数都做了哪些事情?

(1)填写偏移量表格地址

 

(2)调用基类构造函数

 

(3)填写派生类虚表地址

 

(4)重写属于基类的虚表地址

 

(5)派生类与基类之间用0分隔

 

 

 

 

      

 

相关内容推荐