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,实现了基类指针指向子类对象的效果,可以实现多态。这是面向对象编程中非常重要的概念。

相关推荐
一律清风1 小时前
QT-文件创建时间修改器
c++·qt
不知所云,1 小时前
qt cmake自定义资源目录,手动加载资源(图片, qss文件)
开发语言·qt
风清扬_jd1 小时前
Chromium 如何定义一个chrome.settingsPrivate接口给前端调用c++
前端·c++·chrome
安冬的码畜日常1 小时前
【玩转 JS 函数式编程_006】2.2 小试牛刀:用函数式编程(FP)实现事件只触发一次
开发语言·前端·javascript·函数式编程·tdd·fp·jasmine
阑梦清川2 小时前
Java继承、final/protected说明、super/this辨析
java·开发语言
PythonFun2 小时前
Python批量下载PPT模块并实现自动解压
开发语言·python·powerpoint
Death2002 小时前
Qt 6 相比 Qt 5 的主要提升与更新
开发语言·c++·qt·交互·数据可视化
机器视觉知识推荐、就业指导2 小时前
使用Qt实现实时数据动态绘制的折线图示例
开发语言·qt
快乐就好ya3 小时前
Java多线程
java·开发语言
CS_GaoMing3 小时前
Centos7 JDK 多版本管理与 Maven 构建问题和注意!
java·开发语言·maven·centos7·java多版本