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

相关推荐
傻啦嘿哟25 分钟前
Python 办公实战:用 python-docx 自动生成 Word 文档
开发语言·c#
翻滚吧键盘29 分钟前
js代码09
开发语言·javascript·ecmascript
q5673152335 分钟前
R语言初学者爬虫简单模板
开发语言·爬虫·r语言·iphone
??tobenewyorker1 小时前
力扣打卡第二十一天 中后遍历+中前遍历 构造二叉树
数据结构·c++·算法·leetcode
rzl021 小时前
java web5(黑马)
java·开发语言·前端
时序数据说1 小时前
为什么时序数据库IoTDB选择Java作为开发语言
java·大数据·开发语言·数据库·物联网·时序数据库·iotdb
jingling5552 小时前
面试版-前端开发核心知识
开发语言·前端·javascript·vue.js·面试·前端框架
oioihoii2 小时前
C++11 forward_list 从基础到精通:原理、实践与性能优化
c++·性能优化·list
m0_687399842 小时前
写一个Ununtu C++ 程序,调用ffmpeg API, 来判断一个数字电影的视频文件mxf 是不是Jpeg2000?
开发语言·c++·ffmpeg
爱上语文2 小时前
Redis基础(5):Redis的Java客户端
java·开发语言·数据库·redis·后端