c++ 重写 多态

1 重写(继承后(拼接基类后))

1.1 非虚函数 同名成员函数 (各自有一个xFunction() 内存 )

cpp 复制代码
#include <iostream>
#include <String>
class BaseClass {
public:
  void xFunction() {
    std::cout << "BaseClass::xFunction()\n";  
  }
};

class Subclass1 : public BaseClass { 
public:
  void xFunction() {
    std::cout << "Subclass1::xFunction()\n";

  }  
};


int main() {
  Subclass1 subclass1;
  subclass1.xFunction();
  return 0;  
}

输出:

Subclass1::xFunction()

cpp 复制代码
基类对象内存布局:
+-------------+ 
| 其他成员变量 |
+-------------+
| xFunction() | -> 基类xFunction()函数的代码      
+-------------+

子类对象内存布局:  
+-------------+
| 基类部分   |   // 继承而来的基类的数据和方法
+-------------+ 
| 子类独有成员变量 |    
+-------------+
| xFunction() | -> 子类xFunction()函数的代码  
+-------------+

运行原则是:

  1. 子类对象可以直接访问继承而来的基类的数据和方法
  2. 当子类与基类存在同名函数时,根据就近原则,通过子类对象访问同名函数时,会调用子类自己的同名函数,即这里的Subclass1::xFunction()
  3. 如果要访问基类中被隐藏的同名函数,需要使用作用域解析运算符,如subclass1.BaseClass::xFunction()

所以在这个例子中,通过subclass1.xFunction()调用时,执行的就是子类中重写的xFunction()函数,输出"Subclass1::xFunction()"。

1.1.2 多次实例化subclass1对象 (就是多次创建应用这个类 开内存)

每个实例化对像的成员变量 内存是单独的

成员函数是多个此类实例对象 公用子类 基类的成员函数 用类:: 指明

成员函数代码区(共享):

┌──────────────────────────────┐
│ 成员函数代码                  │  
│ (包括 BaseClass::xFunction)  │
│ (包括 Subclass1::xFunction)  │
└──────────────────────────────┘

subclass1对象实例1:
┌──────────────────────────────┐
│ 成员变量                      │ 
└──────────────────────────────┘

subclass1对象实例2: 
┌──────────────────────────────┐
│ 成员变量                      │
└──────────────────────────────┘

1.2 虚函数virtual (只有一个xFunction()内存 在基类中, 重写就覆盖)

cpp 复制代码
#include <iostream>
#include <String>
class BaseClass {
public:
  virtual void xFunction() {
    std::cout << "BaseClass::xFunction()\n";  
  }
};

class Subclass1 : public BaseClass { 
public:
  void xFunction() {
    std::cout << "Subclass1::xFunction()\n";

  }  
};


int main() {
  Subclass1 subclass1;
  subclass1.xFunction();
  return 0;  
}
cpp 复制代码
+------------------------+
|        subclass1       |
+------------------------+
|  vptr (指向虚函数表)   |
+------------------------+
|                        |
|                        |
|                        |
|                        |
|                        |
|                        |
|                        |
|                        |
+------------------------+

+------------------------+
|       BaseClass        |
+------------------------+
|  vtable (虚函数表)     |
+------------------------+
|  xFunction()           |
+------------------------+

就是subclass1存的是基类的xFunction()地址的地址?

是的,您的理解是正确的。
subclass1中存的是指向基类中xFunction()这个成员函数的指针的地址。
所以它是一个二级指针。

2 多态(子类用基类模板创建/增加不同功能)

cpp 复制代码
#include <iostream>

class Operation {
public:
    virtual int calculate(int a, int b) = 0; // 纯虚函数,需要在子类中实现
};

class Addition : public Operation {
public:
    int calculate(int a, int b) override {
        return a + b;
    }
};

class Subtraction : public Operation {
public:
    int calculate(int a, int b) override {
        return a - b;
    }
};

int main() {
    Operation* op1 = new Addition(); // 创建加法类对象,并将其指针赋值给基类指针
    Operation* op2 = new Subtraction(); // 创建减法类对象,并将其指针赋值给基类指针

    int result1 = op1->calculate(5, 3); // 调用加法类的calculate函数
    int result2 = op2->calculate(5, 3); // 调用减法类的calculate函数

    std::cout << "Result1: " << result1 << std::endl; // 输出加法计算结果
    std::cout << "Result2: " << result2 << std::endl; // 输出减法计算结果

    delete op1;
    delete op2;

    return 0;
}

Operation* op1 = new Addition(); 创建对象并开内存 并给基类一个初始地址,;

然后根据这个地址 基类分配各个成员的空间;

初始化完 基类Operation被改造有成员变量calculate();

子类 只有指向基类的地址 用于找到虚函数 成员变量;
+------------------------+

| Operation |

+------------------------+

| vtable (虚函数表) |

+------------------------+

| calculate() |

+------------------------+

+------------------------+

| Subtraction |

+------------------------+

| vptr (指向虚函数表) |

+------------------------+

3

3.1

cpp 复制代码
Operation* op1 = new Addition();

3.2 & 取地址符号

cpp 复制代码
Addition add; // 创建命名的 Addition 对象
Operation* op1 = &add; // 将对象的地址赋值给基类指针

是的,Operation* op1 = new Addition();这一行代码是在堆内存上动态分配了一个Addition对象。

具体来说:

  1. new Addition() 在堆内存上创建了一个Addition对象,并返回该对象的地址

  2. Operation* op1 定义了一个Operation类型的指针op1

  3. = 将new Addition()返回的Addition对象的地址赋值给了指针op1

所以,op1指向了堆内存中动态分配的那个Addition对象。

而Addition add这行代码是在栈内存上创建了一个Addition类型的对象add。

两者的区别在于:

  1. new创建的是在堆内存上的对象
  2. 直接创建如Addition add的是在栈内存上的对象

堆内存对象的生命周期由程序员控制,栈内存对象的生命周期随着函数的结束而结束。

将Addition对象的地址赋值给Operation*类型的指针op1,实现了基类指针指向子类对象的效果,可以实现多态。这是面向对象编程中非常重要的概念。

相关推荐
yuyanjingtao9 分钟前
CCF-GESP 等级考试 2023年12月认证C++三级真题解析
c++·青少年编程·gesp·csp-j/s·编程等级考试
雨颜纸伞(hzs)11 分钟前
C语言介绍
c语言·开发语言·软件工程
J总裁的小芒果12 分钟前
THREE.js 入门(六) 纹理、uv坐标
开发语言·javascript·uv
坊钰41 分钟前
【Java 数据结构】移除链表元素
java·开发语言·数据结构·学习·链表
chenziang11 小时前
leetcode hot100 LRU缓存
java·开发语言
时雨h1 小时前
RuoYi-ue前端分离版部署流程
java·开发语言·前端
云计算DevOps-韩老师1 小时前
【网络云计算】2024第52周-每日【2024/12/25】小测-理论&实操-自己构造场景,写5个系统管理的脚本-解析
开发语言·网络·云计算·bash·perl
暮色尽染1 小时前
Python 正则表达式
开发语言·python
IT猿手1 小时前
最新高性能多目标优化算法:多目标麋鹿优化算法(MOEHO)求解GLSMOP1-GLSMOP9及工程应用---盘式制动器设计,提供完整MATLAB代码
开发语言·算法·机器学习·matlab·强化学习
小爬虫程序猿1 小时前
利用Java爬虫获取速卖通(AliExpress)商品详情的详细指南
java·开发语言·爬虫