【c++】多态&多态对象模型

来源:互联网 发布:算法导论 原版 编辑:程序博客网 时间:2024/06/05 18:33

1.多态:

在C ++程序设计中,多态性是指具有不同功能的函数可以用同一个函数名,这样就可以用一个函数名调用不同内容的函数。在面向对象方法中一般是这样表述多态性的:向不同的对象发送同一个消息, 不同的对象在接收时会产生不同的行为(即方法)。也就是说,每个对象可以用自己的方式去响应共同的消息。所谓消息,就是调用函数,不同的行为就是指不同的实现,即执行不同的函数。从系统实现的角度看,多态性分为两类:静态多态性和动态多态性。以前学过的函数重载和运算符重载实现的多态性属于静态多态性,在程序编译时系统就能决定调用的是哪个函数,因此静态多态性又称编译时的多态性。静态多态性是通过函数的重载实现的(运算符重载实质上也是函数重载)。动态多态性是在程序运行过程中才动态地确定操作所针对的对象。它又称运行时的多态性。动态多态性是通过虚函数(Virtual fiinction)实现的。

当使用基类的指针或引用调用重写的虚函数时,当指向父类调用的就是父类的虚函数,当指向子类调用的就是子类的虚函数。

例:

class Person  //父类
{
public:
 virtual void BuyTickets()
 {
  cout << "买票" << endl;
 }
protected:
 string _name;
};
class Student :public Person //子类
{
public:
 virtual void BuyTickets()
 {
  cout << "买票-半价" << endl;
 }
protected:
 int _num; //学号
};
void fun(Person&p)
{
 p.BuyTickets();
}
void test()
{
 Person p;
 Student s;
 fun(p);
 fun(s);
}

虚函数:类成员函数前加virtual

虚函数重写:当在子类定义了一个与父类完全相同的虚函数,则称子类的这个函数重写了父类这个函数。

2.多态的对象模型(单继承&多继承)

1.单继承

class Base
{
public:
 virtual void func1()
 {
  cout << "Base::func1" << endl;
 }
 virtual void func2()
 {
  cout << "Base::func2" << endl;
 }
private:
 int a;
};
class Derive :public Base
{
public:
 virtual void func1()
 {
  cout << "Derive::func1" << endl;
 }
 virtual void func3()
 {
  cout << "Derive::func3" << endl;
 }
 virtual void func4()
 {
  cout << "Derive::func4" << endl;
 }
private:
 int b;
};
typedef void(*FUNC)();
void PrintVTable(int *VTable)
{
 cout << "虚表地址:" << VTable << endl;
 for (int i = 0; VTable[i] != 0; ++i)
 {
  printf("第%d个虚函数地址:0X%x,->", i, VTable[i]);
  FUNC f = (FUNC)VTable[i];
  f();
 }
 cout << endl;
}
void Test1()
{
 Base b1;
 Derive d1;
 int*VTable1 = (int*)(*(int*)&b1);
 int*VTable2 = (int*)(*(int*)&d1);
 PrintVTable(VTable1);
 PrintVTable(VTable2);

}

可以看出派生类Derive::fun1重写基类Base::fun1,覆盖了相应虚表位置上的函数。


2.多继承

class Base1
{
public:
 virtual void func1()
 {
  cout << "Base::func1" << endl;
 }
 virtual void func2()
 {
  cout << "Base::func2" << endl;
 }
private:
 int b1;
};
class Base2
{
public:
 virtual void func1()
 {
  cout << "Base::func1" << endl;
 }
 virtual void func2()
 {
  cout << "Base::func2" << endl;
 }
private:
 int b2;
};
class Derive :public Base1, public Base2
{
public:
 virtual void func1()
 {
  cout << "Derive::func1" << endl;
 }
 virtual void func3()
 {
  cout << "Derive::func3" << endl;
 }
private:
 int d1;
};
typedef void(*FUNC)();
void PrintVTable(int *VTable)
{
 cout << "虚表地址:" << VTable << endl;
 for (int i = 0; VTable[i] != 0; ++i)
 {
  printf("第%d个虚函数地址:0X%x,->", i, VTable[i]);
  FUNC f = (FUNC)VTable[i];
  f();
 }
 cout << endl;
}
void Test1()
{
 Derive d1;
 int*VTable = (int*)(*(int*)&d1);
 PrintVTable(VTable);
 //Base2虚函数表在对象Base1后面
 VTable = (int*)(*((int*)&d1 + sizeof(Base1) / 4));
 PrintVTable(VTable);
}

内存布局:

3.菱形继承

什么是菱形继承?通过这个图大家就可以很直观的理解啦

如上图,菱形继承即多个类继承了同一个公共基类,而这些派生类又同时被一个类继承。这么做会引发什么问题呢?

通过该代码,我们可以看出当我们想要调用我们从Base里继承的fun时就会出现调用不明确问题,并且会造成数据冗余的问题。

我们可以使用域限定我们所要访问的函数,c++也给我们了另一个解决方案--虚继承。

原创粉丝点击