说一下多态
多态就是不同的继承类对象,针对同一消息做出不同的响应,父类的指针指向或者绑定到子类的对象,使得父类指针呈现多种不同的表现方式。 要实现多态,首先父类需要有一个virtual修饰的虚方法,子类要重写父类的虚方法。父类的指针绑定子类的对象。 多态是通过虚函数表实现的,调用虚方法时,父类指针指向子类的虚表指针,虚表指针指向子类的虚函数表,通过遍历子类的虚函数表,找到对应的虚方法。 由于子类对象重写的父类的虚方法,在虚函数表中达成覆盖,所以通过父类的指针就可以调用子类的方法。从而达到多态。
多态概念
通俗来说,多态就是多种形态,具体点就是去完成某种行为,不同的类去完成就会产生不同的形态。 比如一个Active方法,包含了吃、走、爬、飞等行为,当调用这个方法,蜗牛就是爬,鸟就是飞。
class Base
{
virtual void fun(){}
virtual Base* fun(){}
virtual ~Base()
}
class D : public Base
{
virtual void fun(){}
virtual Base* fun(){}
virtual ~D(){}
}
虚方法
被virtual修饰的类成员方法就是虚方法/虚函数 一个类中有了虚方法就会增加虚表指针存放虚方法的地址 在内存中多占一个空间。
多态的定义和实现
多态的条件:
- 父类有virtual虚方法
- 子类重写了父类的虚方法
- 通过父类的指针/引用接收不同的子类(向上转换)
重载、重写、隐藏
重载:
class A
{
public:
void fun(){}
void fun(int a){}
void fun(int a,int b){}
int fun(){}
};
同名隐藏:
class A
{
public:
void fun();
}
class B : public A
{
public:
void fun(){}
int fun(int a){}
}
重写
class A
{
public:
void fun();
}
class B : public A
{
public:
void fun(){}
}
重写例外:
协变
class A
{
public:
A* fun();
}
class B : public A
{
public:
B* fun(){}
}
返回值不同,父类返回父类指针/引用,子类返回子类指针/引用,这是可以达成重写的。 原因是,继承赋值兼容规则的向上转换。 析构方法重写/析构多态 当使用父类指针接收子类对象时,Base* pb = new D;构造没有任何问题,delete D析构时却会产生问题,由于D这块空间给了父类指针,那么pb只能观察到父类所在的范围,就不会去调用子类的析构方法,这就有可能导致子类申请的空间来不及释放或不能释放,造成内存泄漏。 给父子类析构方法加上virtual变成虚方法,就可以达成析构重写(函数名不同,所以是重写的例外),就可以调用到子类的析构方法。
单继承和多继承中虚函数表
Base类的虚函数表:
class Base {
public:
virtual void f() { cout << "Base::f" <<endl;}
virtual void g() { cout << "Base::g" <<endl;}
virtual void h() { cout << "Base::h" <<endl;}
};
typedef void(*Fun)(void);
Base b;
Fun pFun = NULL;
cout << "虚函数表地址:" << (int*)(&b) <<endl;
cout << "虚函数表 — 第一个函数地址:" << (int*)*(int*)(&b) <<endl;
pFun = (Fun)*((int*)*(int*)(&b));
pFun();
(Fun)*((int*)*(int*)(&b)+0);
(Fun)*((int*)*(int*)(&b)+1);
(Fun)*((int*)*(int*)(&b)+2);
Base类对象的内存结构图: 单继承 未重写:
class A:public Base
{
void f1() { cout << "A::f" <<endl;}
void g1() { cout << "A::g" <<endl;}
void h1() { cout << "A::h" <<endl;}
};
A实例的成员内存图 重写:
class A:public Base
{
virtual void f() { cout << "A::f" <<endl;}
void g1() { cout << "A::g" <<endl;}
void h1() { cout << "A::h" <<endl;}
};
A类实例的成员内存图:
多继承: 无覆盖:
class A:public Base1,public Base2,public Base3
{
void f1() { cout << "A::f" <<endl;}
void g1() { cout << "A::g" <<endl;}
void h1() { cout << "A::h" <<endl;}
};
有覆盖:
class A:public Base1,public Base2,public Base3
{
virtual void f() { cout << "A::f" <<endl;}
void g() { cout << "A::g" <<endl;}
void h() { cout << "A::h" <<endl;}
};
|