news 2026/6/6 14:41:14

很有意思的一段代码(再次复习多态)

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
很有意思的一段代码(再次复习多态)

目录

很有意思的一段代码

我用最底层、最直白、最透彻的方式给你讲清楚!

🔥 最终答案(一句话击穿本质)

hello () 是纯虚函数 / 虚函数 → 会触发「动态多态」

多态的规则:永远看「对象真实类型」,不看在哪调用!

🚀 我一步步带你走执行流程(超级清晰)

1. 调用 a->func()

2. 进入 Son::func ()

3. 进入 Base::func ()

4. 执行 hello();

重点来了!

当前对象是谁?

→ 对象是 Son

→ 调用 Son::hello()

🎯 最终执行流程

💡 为什么不调用父类 hello?

🚀 你想让它调用父类 hello?

🎯 最终终极总结(背下来,C++ 多态永远不晕)

虚函数 ≠ 看在哪调用,只看对象是谁!

对象是 Son → 所有虚函数都优先调用 Son 里的!

不管在父类调用、子类调用,结果都一样!

🔥底层原理:虚函数表(vtable)+ 虚指针(vfptr)

一、先看你的代码关键点

关键点:

二、编译器会自动生成 虚函数表 vtable

1️⃣ Base 类的虚表

2️⃣ Son 类的虚表

三、每个对象内部都有一个 虚指针 __vfptr

四、现在开始执行:a->func ()

第 1 步

第 2 步

第 3 步 进入父类 func

第 4 步 执行 hello ()

五、最终执行流程(超级清晰)

六、最终输出

七、最核心结论(背下来!)

虚函数调用规则:永远看对象是谁,不看在哪调用!

八、一句话总结

对象是 Son → 虚表是 Son → 所有虚函数都优先用子类重写版本!

🔥 终极、最准确、最透彻回答:父类构造函数能不能私有?

🎯 1. 直接回答你

如果这个类要被继承 → 构造函数 绝对不能 是 private!

如果这个类不被继承(比如单例)→ 构造函数 可以 是 private!

🎯 2. 为什么被继承时不能私有?

创建子类对象,必须先调用父类构造函数!

🎯 3. 父类构造函数必须是什么权限?

✅ public(公开)

✅ protected(保护,只能子类访问)

🎯 4. 什么时候构造函数 可以 是 private?(只有 2 种场景)

① 单例模式(最常用!)

② 禁止创建对象(工具类)

🎯 5. 最关键总结(背会,面试 / 考试满分)

🔴 要被继承 → 构造不能 private

🟢 不被继承 → 构造可以 private

🟡 单例模式 → 构造必须 private

🎯 6. 回到你的代码

✅ Base 构造必须是 public / protected

❌ 绝对不能是 private


很有意思的一段代码

#include <qdebug.h> class Base { //private: //ERROR public: Base::Base() { qDebug()<<"Base"; } public: virtual void hello()= 0; // virtual void hello() // { // qDebug()<<"父类hello"; // // } //virtual void helloy()= 0; virtual void helloy() { qDebug()<<"父类hello1111"; } virtual void func(){ hello(); helloy(); qDebug()<<"父类"; } }; class Son:public Base{ public: Son::Son() { qDebug()<<"Son"; } void func()override{ Base::func(); // 【强制调用父类实现,不看多态】 helloy(); qDebug()<<"子类"; } virtual void hello() { qDebug()<<"子类hello"; } }; int main(int argc, char *argv[]) { Base * a = new Son; // Son a = Son; a->func(); }

我用最底层、最直白、最透彻的方式给你讲清楚!

为什么父类 func () 里调用 hello (),最终跑到子类 hello ()?

我保证你看完彻底懂多态


🔥 最终答案(一句话击穿本质)

hello () 是纯虚函数 / 虚函数 → 会触发「动态多态」

多态的规则:永远看「对象真实类型」,不看在哪调用!

你现在的对象是Son所以不管在父类里调用还是子类里调用hello () 一定调用子类的!


🚀 我一步步带你走执行流程(超级清晰)

你写的代码:

cpp

运行

Base *a = new Son; // 关键点:对象是 Son! a->func();

1. 调用a->func()

  • 指针是Base*
  • 对象是Son
  • 所以调用Son::func()

2. 进入 Son::func ()

cpp

运行

void func() override { Base::func(); <-- 进入父类func helloy(); qDebug()<<"子类"; }

3. 进入 Base::func ()

cpp

运行

virtual void func() { hello(); <-- 这里!!! helloy(); qDebug()<<"父类"; }

4. 执行hello();

重点来了!

hello()虚函数(你写的是=0纯虚函数)只要是虚函数,没有写Base::,就一定触发多态!

多态只看一个东西:

当前对象是谁?

→ 对象是Son

→ 调用Son::hello()


🎯 最终执行流程

plaintext

a->func() ↳ Son::func() ↳ Base::func() ↳ hello() 【多态 → 对象是Son】 ↳ Son::hello() ↳ helloy() 【多态 → Son::helloy()】 ↳ 打印父类 ↳ helloy() ↳ 打印子类

💡 为什么不调用父类 hello?

因为父类hello()是:

cpp

运行

virtual void hello() = 0;

纯虚函数 → 没有实现,必须由子类实现而且就算有实现,只要是虚函数,就会多态调用子类


🚀 你想让它调用父类 hello?

必须强制关闭多态

cpp

运行

void func() { Base::hello(); <-- 加类名::,关闭多态 }

🎯 最终终极总结(背下来,C++ 多态永远不晕)

虚函数 ≠ 看在哪调用,只看对象是谁!

对象是 Son → 所有虚函数都优先调用 Son 里的!

不管在父类调用、子类调用,结果都一样!


你现在彻底懂了吗?我可以给你画虚函数表(vtable)底层结构图,让你彻底看透底层!

需要

🔥底层原理:虚函数表(vtable)+ 虚指针(vfptr)

我用最简单、最直观、最底层的方式,给你讲明白为什么父类调用 hello (),却跑到子类去了


一、先看你的代码关键点

cpp

运行

class Base { public: virtual void hello() = 0; // 纯虚函数 virtual void helloy(); virtual void func(); }; class Son : public Base { public: void hello() override; // 子类重写 void func() override; };

你创建对象:

cpp

运行

Base* a = new Son;

关键点:

*a 的类型是 Base,但真实对象是 Son!**


二、编译器会自动生成虚函数表 vtable

1️⃣ Base 类的虚表

plaintext

Base 的虚表: [0] = Base::hello (纯虚,没有实现) [1] = Base::helloy [2] = Base::func

2️⃣ Son 类的虚表

子类重写了哪些虚函数,虚表里就替换成子类的函数!

plaintext

Son 的虚表: [0] = Son::hello (重写了!) [1] = Base::helloy (没重写,用父类) [2] = Son::func (重写了!)

三、每个对象内部都有一个虚指针 __vfptr

当你创建:

plaintext

new Son

这个对象内部会自动生成一个指针:

plaintext

__vfptr → Son 的虚表

永远指向自己类的虚表!


四、现在开始执行:a->func ()

第 1 步

cpp

运行

a->func();
  • 看虚表:Son 的虚表
  • func 对应:Son::func()

第 2 步

cpp

运行

void Son::func() { Base::func(); // 调用父类func }

第 3 步 进入父类 func

cpp

运行

void Base::func() { hello(); // 🔥 关键在这里!!! }

第 4 步 执行 hello ()

hello 是虚函数 →查虚表!

  • 对象是 Son
  • 虚表是 Son 的虚表
  • hello 对应:Son::hello()

五、最终执行流程(超级清晰)

plaintext

a->func() ↳ Son::func() ↳ Base::func() ↳ hello() 查虚表 → Son::hello() ↳ helloy() 查虚表 → Base::helloy ↳ 输出 "父类" ↳ helloy() ↳ 输出 "子类"

六、最终输出

plaintext

子类hello 父类hello1111 父类 父类hello1111 子类

七、最核心结论(背下来!)

虚函数调用规则:永远看对象是谁,不看在哪调用!

  • 在父类里调用 →多态
  • 在子类里调用 →多态
  • 只要是虚函数 →查虚表
  • 虚表由真实对象类型决定

八、一句话总结

对象是 Son → 虚表是 Son → 所有虚函数都优先用子类重写版本!


如果你愿意,我可以给你画👉 汇编级别底层调用流程让你彻底精通 C++ 多态底层!

父类的构造函数可以是私有的吗

🔥终极、最准确、最透彻回答:父类构造函数能不能私有?

我给你一句话总结 + 底层原理 + 什么时候能、什么时候不能,看完你永远不会再错!


🎯1. 直接回答你

如果这个类要被继承 → 构造函数 绝对不能 是 private!

如果这个类不被继承(比如单例)→ 构造函数 可以 是 private!


🎯2. 为什么被继承时不能私有?

因为C++ 继承的铁律

创建子类对象,必须先调用父类构造函数!

plaintext

创建 Son 对象 ↓ 自动调用 Son 构造 ↓ 【偷偷、自动、必须】调用父类 Base 构造

如果父类构造是private

  • 子类无权访问
  • 无法创建对象
  • 编译器直接报错:base class 'Base' has private default constructor

🎯3. 父类构造函数必须是什么权限?

必须是:

public(公开)

protected(保护,只能子类访问)

绝对不能是 private!


🎯4. 什么时候构造函数 可以 是 private?(只有 2 种场景)

① 单例模式(最常用!)

目的:只允许创建一个对象,禁止外部new

cpp

运行

class Singleton { private: Singleton() {} // 构造私有 ✅ 允许 public: static Singleton& getInstance() { static Singleton obj; return obj; } };

不被继承 → 构造可以私有


② 禁止创建对象(工具类)

cpp

运行

class Tool { private: Tool() {} // 私有 ✅ 允许 public: static void doSomething() {} };

只调用静态方法,不创建对象 → 构造可以私有


🎯5. 最关键总结(背会,面试 / 考试满分)

🔴要被继承 → 构造不能 private

🟢不被继承 → 构造可以 private

🟡单例模式 → 构造必须 private


🎯6. 回到你的代码

你写的是:

cpp

运行

class Son : public Base

你在继承!所以:

✅ Base 构造必须是public / protected

❌ 绝对不能是private

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/6/6 14:39:26

嵌入式调试利器USMART 2.0:串口交互式函数调用组件详解与实战

1. 项目概述&#xff1a;嵌入式调试的“瑞士军刀”在嵌入式开发&#xff0c;尤其是MCU裸机或RTOS应用开发中&#xff0c;调试一直是个既基础又令人头疼的环节。传统的调试方式&#xff0c;比如修改一个参数、测试一个函数&#xff0c;往往意味着&#xff1a;修改代码 -> 编译…

作者头像 李华
网站建设 2026/6/6 14:38:52

如何完整备份QQ空间历史记录:开源工具的终极实践指南

如何完整备份QQ空间历史记录&#xff1a;开源工具的终极实践指南 【免费下载链接】GetQzonehistory 获取QQ空间发布的历史说说 项目地址: https://gitcode.com/GitHub_Trending/ge/GetQzonehistory 你是否曾经想找回那些年写下的QQ空间说说&#xff0c;却发现只能看到最…

作者头像 李华
网站建设 2026/6/6 14:35:09

Ultimate SD Upscale完整教程:AI图像无损放大终极方案

Ultimate SD Upscale完整教程&#xff1a;AI图像无损放大终极方案 【免费下载链接】ultimate-upscale-for-automatic1111 项目地址: https://gitcode.com/gh_mirrors/ul/ultimate-upscale-for-automatic1111 Ultimate SD Upscale是AUTOMATIC1111 Stable Diffusion web …

作者头像 李华
网站建设 2026/6/6 14:33:07

PCB焊盘设计全解析:从物理原理到SMT/BGA实战避坑指南

1. 焊盘设计&#xff1a;决定PCB焊接质量的第一道关口在电子硬件开发这个行当里摸爬滚打了十几年&#xff0c;我越来越深刻地体会到&#xff0c;一个产品的可靠性&#xff0c;往往在PCB设计阶段就已经被决定了。尤其是焊盘设计&#xff0c;这个看似不起眼的环节&#xff0c;实则…

作者头像 李华
网站建设 2026/6/6 14:33:06

逆多普勒效应与负折射率光子晶体:从原理到硬件应用

1. 从科幻到现实&#xff1a;逆多普勒效应与光子晶体的突破最近&#xff0c;上海理工大学光学工程团队在《自然光子学》上发表的一项研究成果&#xff0c;让“隐形斗篷”这个科幻迷们津津乐道的概念&#xff0c;再次被推到了科技前沿的聚光灯下。不过&#xff0c;这次不再是纯粹…

作者头像 李华