多态的实现原理分析

1.成员函数加上virtual修饰后,sizeof(类)的数字变大,即使有多个成员函数声明成虚函数,sizeof(类)的数字不会再变大。

加了virtual后,用GDB调试的时候,发现对象b下多了个_vptr


#include <iostream>


using namespace std;


class Base{


public:


Base() : x(0){


}


~Base(){


}


virtual void show(){


cout << "Base show" << endl;


}


private:


int x;


};


int main(){


cout << sizeof(Base) << endl;//16


Base b;


}


没加virtual的效果:


#include <iostream>


using namespace std;


class Base{


public:


Base() : x(0){


}


~Base(){


}


void show(){


cout << "Base show" << endl;


}


private:


int x;


};


int main(){


cout << sizeof(Base) << endl;//16


Base b;


}多态的实现原理分析

2.声明了虚拟函数后,系统会自动维护一个指针_vptr,指向虚函数列表。


多态是通过虚函数列表实现的。


#include <iostream>


using namespace std;


class Base{


public:


Base() : x(0){


}


~Base(){


}


virtual void show(){


cout << "Base show" << endl;


}


virtual void print(){


cout << "Base print" << endl;


}


void fun(){


cout << "Base fun" << endl;


}


private:


int x;


};


class D : public Base{


public:


D() : y(0){


}


~D(){


}


void show(){


cout << "D show" << endl;


}


void fun(){


cout << "D fun" << endl;


}


virtual void list(){


cout << "D list" << endl;


}


private:


int y;


};


int main(){


D d;


d.fun();//调用子类的fun方法,父类的fun方法被隐藏了


Base *pb = &d;


pb->show();//调用子类的show方法,多态(覆盖)


pb->fun();//调用父类的fun方法


Base &fb = d;


fb.show();//用子类的show方法,多态(覆盖)


fb.fun();//调用父类的fun方法


}


3.虚函数表多态的实现原理分析


3.1 单继承,无覆盖


#include <iostream>


using namespace std;


class Base{


public:


virtual void f(){}


virtual void g(){}


virtual void h(){}


};


class D : public Base{


virtual void f1(){}


virtual void g1(){}


virtual void h1(){}


};


int main(){


D d;


}


gdb的分析结果:


18 D d;


(gdb) n


(gdb) p d


$2 = {<Base> = {_vptr.Base = 0x555555755d48 <vtable for D+16>}, <No data fields>}


(gdb) p (long*)*((long*)0x555555755d48)


$3 = (long *) 0x555555554a06 <Base::f()>//虚函数表第1个地址


(gdb) p (long*)*((long*)0x555555755d48+1)


$4 = (long *) 0x555555554a12 <Base::g()>//虚函数表第2个地址


(gdb) p (long*)*((long*)0x555555755d48+2)


$5 = (long *) 0x555555554a1e <Base::h()>//虚函数表第3个地址


(gdb) p (long*)*((long*)0x555555755d48+3)


$6 = (long *) 0x555555554a2a <D::f1()>//虚函数表第4个地址


(gdb) p (long*)*((long*)0x555555755d48+4)


$7 = (long *) 0x555555554a36 <D::g1()>//虚函数表第5个地址


(gdb) p (long*)*((long*)0x555555755d48+5)


$8 = (long *) 0x555555554a42 <D::h1()>//虚函数表第6个地址


(gdb) p (long*)*((long*)0x555555755d48+6)


$9 = (long *) 0x7ffff7dc7438 <vtable for __cxxabiv1::__si_class_type_info+16>


3.2 单继承,覆盖


#include <iostream>


using namespace std;


class Base{


public:


virtual void f(){}


virtual void g(){}


virtual void h(){}


};


class D : public Base{


virtual void f(){}


virtual void g1(){}


virtual void h1(){}


};


int main(){


D d;


}


gdb的分析结果:


18 D d;


(gdb) n


(gdb) p d


$1 = {<Base> = {_vptr.Base = 0x555555755d50 <vtable for D+16>}, <No data fields>}


(gdb) p (long*)*((long*)0x555555755d50)


$2 = (long *) 0x555555554a0e <D::f()>//虚函数表第1个地址(变成了子类的f())


(gdb) p (long*)*((long*)0x555555755d50+1)


$3 = (long *) 0x5555555549f6 <Base::g()>//虚函数表第2个地址


(gdb) p (long*)*((long*)0x555555755d50+2)


$4 = (long *) 0x555555554a02 <Base::h()>//虚函数表第3个地址


(gdb) p (long*)*((long*)0x555555755d50+3)


$5 = (long *) 0x555555554a1a <D::g1()>//虚函数表第4个地址


(gdb) p (long*)*((long*)0x555555755d50+4)


$6 = (long *) 0x555555554a26 <D::h1()>//虚函数表第5个地址


(gdb) p (long*)*((long*)0x555555755d50+5)


$7 = (long *) 0x7ffff7dc7438 <vtable for __cxxabiv1::__si_class_type_info+16>


3.3 多继承,不覆盖


#include <iostream>


using namespace std;


class Base{


public:


virtual void f(){}


virtual void g(){}


virtual void h(){}


};


class Base1{


public:


virtual void f(){}


virtual void g(){}


virtual void h(){}


};


class Base2{


public:


virtual void f(){}


virtual void g(){}


virtual void h(){}


};


class D : public Base,public Base1,public Base2{


virtual void f1(){}


virtual void g1(){}


virtual void h1(){}


};


int main(){


D d;


}


gdb的分析结果:


29 D d;


(gdb) n


(gdb) p d


$1 = {<Base> = {_vptr.Base = 0x555555755ca8 <vtable for D+16>}, <Base1> = {


_vptr.Base1 = 0x555555755ce8 <vtable for D+80>}, <Base2> = {


_vptr.Base2 = 0x555555755d10 <vtable for D+120>}, <No data fields>}


(gdb) p (long*)*((long*)0x555555755ca8)


$3 = (long *) 0x555555554b6c <Base::f()>//虚函数表(Base)第1个地址


(gdb) p (long*)*((long*)0x555555755ca8+1)


$4 = (long *) 0x555555554b78 <Base::g()>//虚函数表(Base)第2个地址


(gdb) p (long*)*((long*)0x555555755ca8+2)


$5 = (long *) 0x555555554b84 <Base::h()>//虚函数表(Base)第3个地址


(gdb) p (long*)*((long*)0x555555755ca8+3)


$6 = (long *) 0x555555554bd8 <D::f1()>//虚函数表(Base)第4个地址


(gdb) p (long*)*((long*)0x555555755ca8+4)


$7 = (long *) 0x555555554be4 <D::g1()>//虚函数表(Base)第5个地址


(gdb) p (long*)*((long*)0x555555755ca8+5)


$8 = (long *) 0x555555554bf0 <D::h1()>//虚函数表(Base)第6个地址


(gdb) p (long*)*((long*)0x555555755ca8+6)


$9 = (long *) 0xfffffffffffffff8


(gdb) p (long*)*((long*)0x555555755ce8)


$10 = (long *) 0x555555554b90 <Base1::f()>//虚函数表(Base1)第1个地址


(gdb) p (long*)*((long*)0x555555755ce8+1)


$11 = (long *) 0x555555554b9c <Base1::g()>//虚函数表(Base1)第2个地址


(gdb) p (long*)*((long*)0x555555755ce8+2)


$12 = (long *) 0x555555554ba8 <Base1::h()>//虚函数表(Base1)第3个地址


(gdb) p (long*)*((long*)0x555555755ce8+3)


$13 = (long *) 0xfffffffffffffff0


(gdb) p (long*)*((long*)0x555555755d10)


$14 = (long *) 0x555555554bb4 <Base2::f()>//虚函数表(Base2)第1个地址


(gdb) p (long*)*((long*)0x555555755d10+1)


$15 = (long *) 0x555555554bc0 <Base2::g()>//虚函数表(Base2)第2个地址


(gdb) p (long*)*((long*)0x555555755d10+2)


$16 = (long *) 0x555555554bcc <Base2::h()>//虚函数表(Base2)第3个地址


(gdb) p (long*)*((long*)0x555555755d10+3)


$17 = (long *) 0x7ffff7dc74f8 <vtable for __cxxabiv1::__vmi_class_type_info+16>


3.4 多继承,覆盖


#include <iostream>


using namespace std;


class Base{


public:


virtual void f(){}


virtual void g(){}


virtual void h(){}


};


class Base1{


public:


virtual void f(){}


virtual void g(){}


virtual void h(){}


};


class Base2{


public:


virtual void f(){}


virtual void g(){}


virtual void h(){}


};


class D : public Base,public Base1,public Base2{


virtual void f(){}


virtual void g1(){}


virtual void h1(){}


};


int main(){


D d;


}


gdb的分析结果:


29 D d;


(gdb) n


(gdb) p d


$1 = {<Base> = {_vptr.Base = 0x555555755cb0 <vtable for D+16>}, <Base1> = {


_vptr.Base1 = 0x555555755ce8 <vtable for D+72>}, <Base2> = {


_vptr.Base2 = 0x555555755d10 <vtable for D+112>}, <No data fields>}


(gdb) p (long*)*((long*)0x555555755cb0)


$2 = (long *) 0x555555554ba4 <D::f()>//虚函数表(Base)第1个地址(变成了子类的f())


(gdb) p (long*)*((long*)0x555555755cb0+1)


$3 = (long *) 0x555555554b5c <Base::g()>//虚函数表(Base)第2个地址


(gdb) p (long*)*((long*)0x555555755cb0+2)


$4 = (long *) 0x555555554b68 <Base::h()>//虚函数表(Base)第3个地址


(gdb) p (long*)*((long*)0x555555755cb0+3)


$5 = (long *) 0x555555554bbc <D::g1()>//虚函数表(Base)第4个地址


(gdb) p (long*)*((long*)0x555555755cb0+4)


$6 = (long *) 0x555555554bc8 <D::h1()>//虚函数表(Base)第5个地址


(gdb) p (long*)*((long*)0x555555755cb0+5)


$7 = (long *) 0xfffffffffffffff8


(gdb) p (long*)*((long*)0x555555755ce8)


$8 = (long *) 0x555555554bb5 <non-virtual thunk to D::f()>//虚函数表(Base1)第1个地址(变成了子类的f())


(gdb) p (long*)*((long*)0x555555755ce8+1)


$9 = (long *) 0x555555554b74 <Base1::g()>//虚函数表(Base1)第2个地址


(gdb) p (long*)*((long*)0x555555755ce8+2)


$10 = (long *) 0x555555554b80 <Base1::h()>//虚函数表(Base1)第3个地址


(gdb) p (long*)*((long*)0x555555755ce8+3)


$11 = (long *) 0xfffffffffffffff0


(gdb) p (long*)*((long*)0x555555755d10)


$12 = (long *) 0x555555554baf <non-virtual thunk to D::f()>//虚函数表(Base2)第1个地址(变成了子类的f())


(gdb) p (long*)*((long*)0x555555755d10+1)


$13 = (long *) 0x555555554b8c <Base2::g()>//虚函数表(Base2)第2个地址


(gdb) p (long*)*((long*)0x555555755d10+2)


$14 = (long *) 0x555555554b98 <Base2::h()>//虚函数表(Base2)第3个地址


(gdb) p (long*)*((long*)0x555555755d10+3)


$15 = (long *) 0x7ffff7dc74f8 <vtable for __cxxabiv1::__vmi_class_type_info+16>


最后你觉得我们的文章对你有帮助,欢迎关注我,并加一下在评论下方的学习群,学习编码:久伴。你可以随时在上面向我们提问,把你在学习C++过程中所遇到的问题发给我们。我们每天都会按时回复大家的每一个问题,希望久伴可以伴随你从入门到专家。

相关文章: