【語法】C++繼承中遇到的問題及解決方法

目錄

1.子類構造函數中初始化父類成員

2.子類顯式調用父類的析構函數

第一種說法:重定義

反駁:

第二種說法:operator~

3.因編譯器版本過低而出現錯誤


貼主在學習C++的繼承時,遇到了很多問題,覺得很變態,特此發帖分享

1.子類構造函數中初始化父類成員

眾所周知,在子類的構造函數中是不能初始化父類成員的,必須調用父類的構造函數來完成初始化

#include <iostream>
using namespace std;
class base
{
public:base():_a(0){cout << "constructor base \n";}
protected:int _a;
};class derived : public base
{
public:derived():_a(0)//報錯,因為_a是父類成員{cout << "constructor derived \n";}
};

?但有一種情況可能會被誤認為是初始化

#include <iostream>
using namespace std;
class base
{
public:base():_a(0){cout << "constructor base \n";}
protected:int _a;
};class derived : public base
{
public:derived()//:base()這里已經隱式調用了base的構造函數了{_a = 0;cout << "constructor derived \n";}
};

這確實可以運行,但這里其實并不是初始化(initialization),而是賦值(assignment),這里看似沒有調用父類的初始化,但其實會隱式調用構造函數

可以看到,base的構造函數還是被調用了,這就是隱式調用了base的構造函數?

那拷貝構造函數呢?若子類不定義默認構造函數的話,拷貝構造時確實會調用父類的拷貝構造函數完成父類函數的初始化

#include <iostream>
using namespace std;
class base
{
public:base():_a(0){cout << "constructor base \n";}base(const base& b):_a(b._a){cout << "copy constructor base \n";}
protected:int _a;
};class derived : public base
{
public:derived():base(){cout << "constructor derived \n";}
};int main()
{derived a;cout << "\n";derived b(a);return 0;
}

輸出結果:

?可以看到在拷貝構造時,隱式調用了父類的拷貝構造

但如果子類有用戶定義的拷貝構造函數,如果沒有顯式調用父類的拷貝構造函數,編譯器就會隱式調用父類的構造函數

#include <iostream>
using namespace std;
class base
{
public:base():_a(0){cout << "constructor base \n";}base(const base& b):_a(b._a){cout << "copy constructor base \n";}
protected:int _a;
};class derived : public base
{
public:derived():base(){cout << "constructor derived \n";}derived(const derived& d)//子類拷貝構造不顯式調用父類的拷貝構造,會隱式調用父類的構造函數完成父類成員初始化{cout << "copy constructor derived \n";}
};int main()
{derived a;cout << "\n";derived b(a);return 0;
}

輸出結果:

可以看到,在拷貝構造時,編譯器先隱式調用了父類的構造函數

2.子類顯式調用父類的析構函數

眾所周知,子類的析構函數會在被調用完成后自動調用父類的析構函數清理父類成員。因為這樣才能保證子類對象先清理子類成員再清理父類成員的順序。

#include <iostream>
using namespace std;
class base
{
public:base(){cout << "constructor base \n";}~base(){cout << "destructor base \n";}
};class derived : public base
{
public:derived(){cout << "constructor derived \n";}~derived(){~base();cout << "destructor derived \n";}//會報錯
};int main()
{derived a;return 0;
}

報錯:?

當然,對于99%的情況來說,根本用不到顯式調用析構函數,剩下的1%就是placement new?管理內存?的情況

對于這里的報錯,我目前知道兩種說法

第一種說法:重定義

這里的~base和~derived構成重定義(隱藏),但他們兩個函數名不相同啊?這是因為經過編譯器處理后所有的析構函數都會被處理成destructor(為了支持多態),那他們兩個析構函數就是重名函數了,父類的析構函數就會被重定義,此時要想讓編譯器知道你要調用的是父類的析構,就要在前面加上作用域限定符

int main()
{cout << int() <<endl;return 0;
}

反駁:

“隱藏”是非限定名查找的一部分。而析構函數的查找方式有所不同,因此不存在隱藏關系。也沒有所謂的“轉換為特殊名稱 destructor(析構函數)”這樣的過程作為名稱查找的目的。?

如果有大佬知道到底對不對的,歡迎評論區解答!!!

第二種說法:operator~

這里的報錯和是不是繼承沒有關系,因為下面代碼也會報同樣的錯誤

class base
{~base(){cout << "~base \n";}void func(){~base();}
};

這段代碼的執行順序其實是先base(),再~

base()會先構造一個base的臨時對象。這里其實不難理解,就例如int(),會調用int的默認構造函數創建臨時的int變量,它的值是0

int main()
{cout << int() <<endl;return 0;
}

輸出:0

所以base()也一樣,會調用base的默認構造函數來構建一個臨時的base對象

然后會試圖調用base對象的operator~重載,如下圖

#include <iostream>
using namespace std;
class base
{
public:base(){cout << "constructor base \n";}~base(){cout << "destructor base \n";}void operator~(){cout << "operator ~ \n";}
};class derived : public base
{
public:derived(){cout << "constructor derived \n";}~derived(){base::~base();cout << "destructor derived \n";}
};
int main()
{~base();cout <<"\n";base().operator~();//第一行就相當于這么調用return 0;
}

輸出結果:

如上圖,第一個和第一行和第三行的代碼輸出結果相同

所以報錯的原因就是base類沒有operator~重載

流程:先構造一個臨時的base對象,再調用臨時base對象的operator~運算符,最后析構這個臨時的base對象

3.因編譯器版本過低而出現錯誤

?根據第二個問題可以得知,當寫出~base()時,會先構造一個臨時的base對象,然后調用該對象的operator~操作符,最后析構這個臨時base對象

而如果要直接在子類中調用父類析構函數,可以這樣

class derived : public base
{
public:derived(){cout << "constructor derived \n";}~derived(){base::~base();cout << "destructor derived \n";}
};

~base()的前面加上作用域限定符,這樣編譯器就知道你是要調用父類的析構函數,而不是operator~重載。

但如果在父類有operator~重載時,在子類中調用base::~base();呢?

#include <iostream>using namespace std;
class base
{
public:base(){cout << "constructor base \n";}~base(){cout << "destructor base \n";}void operator~(){cout << "operator ~ \n";}
};class derived : public base
{
public:derived(){cout << "constructor derived \n";}~derived(){base::~base();cout << "destructor derived \n";}
};
int main()
{derived d;return 0;
}

上面代碼在我之前的編譯器中,就會編譯錯誤

error:

cmd /c chcp 65001>nul && C:\mingw64\bin\g++.exe -fdiagnostics-color=always -g "D:\Valkyrie-text\simple text\text.cpp" -o "D:\Valkyrie-text\simple text\text.exe"
D:\Valkyrie-text\simple text\text.cpp: In destructor 'derived::~derived()':
D:\Valkyrie-text\simple text\text.cpp:15:28: error: no matching function for call to 'derived::~derived()'~derived(){base::~base();cout << "destructor derived \n";}^
D:\Valkyrie-text\simple text\text.cpp:7:5: note: candidate: 'base::~base()'~base(){cout << "destructor base \n";}^
D:\Valkyrie-text\simple text\text.cpp:7:5: note:   candidate expects 1 argument, 0 provided

后來發現,這是編譯器在抱怨缺少參數

在前面加上thts->就可以了

this->base::~base();

相信又很多人運行上面代碼時都會報和我一樣的錯誤,這是因為編譯器的版本太低

我之前的編譯器是8.1.0的gcc

現在更新了,用14.2.0的版本就不會再報這個錯了,所以強烈建議大家更新一下自己的編譯器!

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/bicheng/78947.shtml
繁體地址,請注明出處:http://hk.pswp.cn/bicheng/78947.shtml
英文地址,請注明出處:http://en.pswp.cn/bicheng/78947.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

前綴和 后綴和 --- 尋找數組的中心下標

題目鏈接 尋找數組的中心下標 給你一個整數數組 nums &#xff0c;請計算數組的 中心下標 。 數組 中心下標 是數組的一個下標&#xff0c;其左側所有元素相加的和等于右側所有元素相加的和。 如果中心下標位于數組最左端&#xff0c;那么左側數之和視為 0 &#xff0c;因為…

NVIDIA --- 端到端自動駕駛

前言 參加了NVIDIA 高級輔助駕駛開發者實驗室的活動&#xff0c;本次活動基于 NVIDIA 汽車行業的端到端解決方案——DRIVE AGX? 平臺&#xff0c;實現高級別智能和安全性的軟硬件開發工具和 AV 基礎設施。并且NVIDIA自動駕駛實驗室推出了一系列自動駕駛算法最新的前沿研究視頻…

SQL實戰:03之SQL中的遞歸查詢

文章目錄 概述SQL 中的遞歸實現題目一:分析組織層級題解題目二:樹節點求解題解步驟一&#xff1a;通過遞歸查詢出每個節點的上級節點和下級節點分布步驟二&#xff1a;分組統計 概述 最近刷題時遇到了一道需要根據組織層級來統計各個層級的一些數據&#xff0c;當時碰到時的第…

MySQL 語法與基礎完全指南

MySQL 是最流行的開源關系型數據庫管理系統之一&#xff0c;廣泛應用于 Web 應用程序開發。本文將全面介紹 MySQL 的基礎知識和完整語法結構。 一、MySQL 基礎概念 1. 數據庫基本術語 數據庫(Database): 存儲數據的集合 表(Table): 數據以表格形式組織 列(Column): 表中的一…

【Sqlalchemy Model轉換成Pydantic Model示例】

【Sqlalchemy Model轉換成Pydantic Model示例】 由于Sqlalchemy和Pydantic的模型字段類型可能有差異, 所以需要一個通用的裝換類 def sqlalchemy_to_pydantic_v2(sqlalchemy_model, pydantic_model):"""通用函數&#xff0c;將 SQLAlchemy 模型實例轉換為 Pyd…

2025年歐洲西南部大停電

2025年4月28日&#xff0c;歐洲西南部出現大規模停電&#xff0c;西班牙、葡萄牙和法國南部均受到影響。有報道指出停電可能與 歐洲電網出現問題有關&#xff0c;但最終原因尚未確定。由于停電&#xff0c;上述地區的交通和通信服務均受到嚴重影響&#xff0c;交通信號燈停止工…

Java EE初階——計算機是如何工作的

1. cpu 馮諾依曼體系&#xff08;Von Neumann Architecture&#xff09; ? CPU 中央處理器: 進?算術運算和邏輯判斷. ? 存儲器: 分為外存和內存, ?于存儲數據(使??進制?式存儲) ? 輸?設備: ??給計算機發號施令的設備. ? 輸出設備: 計算機個??匯報結果的設…

飛鳥游戲模擬器 1.0.3 | 完全免費無廣告,內置大量經典童年游戲,重溫美好回憶

飛鳥游戲模擬器是一款專為安卓用戶設計的免費游戲模擬器&#xff0c;內置了大量經典的童年游戲。該模擬器擁有豐富的游戲資源&#xff0c;目前已有約20,000款游戲&#xff0c;包括多種類型如冒險、動作、角色扮演等。用戶可以直接搜索查找想要玩的游戲進行下載并啟動。游戲庫中…

網絡爬取需謹慎:警惕迷宮陷阱

一、技術背景:網絡爬蟲與數據保護的博弈升級 1. 問題根源:AI訓練數據爬取的無序性 數據需求爆炸:GPT-4、Gemini等大模型依賴數萬億網頁數據訓練,但大量爬蟲無視網站的robots.txt協議(非法律強制),未經許可抓取內容(如新聞、學術論文、代碼),引發版權爭議(如OpenAI被…

Qwen3簡介:大型語言模型的革命

Qwen3簡介&#xff1a;大型語言模型的革命 Qwen系列語言模型的最新發布——Qwen3&#xff0c;標志著人工智能&#xff08;AI&#xff09;技術的一次重大飛躍。基于前代版本的成功&#xff0c;Qwen3在架構、推理能力和多項先進功能上都取得了顯著提升&#xff0c;正在重新定義大…

MODSIM選型指南:汽車與航空航天企業如何選擇仿真平臺

1. 引言 在競爭激烈的汽車與航空航天領域&#xff0c;仿真技術已成為產品研發不可或缺的環節。通過在設計階段驗證概念并優化性能&#xff0c;仿真平臺能有效縮短開發周期并降低物理樣機制作成本。 MODSIM&#xff08;建模與仿真&#xff09;作為達索系統3DEXPERIENCE平臺的核…

linux 內核 debugfs 使用介紹

一&#xff1a;概述 debugfs 是 Linux 內核提供的一個特殊的虛擬文件系統&#xff0c;用于 暴露內核模塊&#xff08;如驅動&#xff09;內部的調試信息或控制接口&#xff0c;供開發者、調試人員實時查看和排查問題。即 debugfs 就是一個“調試專用的 /proc 或 /sys”&#xf…

ZYNQ筆記(十五):PL讀寫PS DDR(自定義IP核-AXI4接口)

版本&#xff1a;Vivado2020.2&#xff08;Vitis&#xff09; 任務&#xff1a;PL 端自定義一個 AXI4 接口的 IP 核&#xff0c;通過 AXI_HP 接口對 PS 端 DDR3 進行讀寫 測試&#xff0c;讀寫的內存大小是 4K 字節&#xff0c; 目錄 一、介紹 &#xff08;1&#xff09;…

Redis 小記

Redis 命令小記 Redis 是一個文本/二進制數據庫&#xff08;textual/binary database&#xff09; CLI 命令 redis-cli, redis-server, redis-benchmark, redis-check-dump, redis-check-aof redis-cli 執行命令 # 方式 1 redis-cli -h 127.0.0.1 -p 6379 > 127.0.0.1:63…

如何在idea中編寫spark程序

在 IntelliJ IDEA 中編寫 Spark 程序的詳細指南 在大數據處理領域&#xff0c;Apache Spark 憑借其強大的分布式計算能力&#xff0c;成為了眾多開發者的首選工具。而 IntelliJ IDEA 作為一款功能強大的集成開發環境&#xff08;IDE&#xff09;&#xff0c;為編寫 Spark 程序…

各類神經網絡學習:(十一)注意力機制(第3/4集),位置編碼

上一篇下一篇注意力機制&#xff08;2/4集&#xff09;注意力機制&#xff08;4/4集&#xff09; 位置編碼 R N N RNN RNN 和 L S T M LSTM LSTM 這些網絡都是串行執行的&#xff0c;在潛移默化中&#xff0c;就包含了順序關系&#xff0c;也就是詞序關系。而注意力機制是并行…

《Python Web部署應知應會》Flask網站隱藏或改變瀏覽器URL:從Nginx反向代理到URL重寫技術

Flask網站隱藏或改變瀏覽器顯示URL地址的實現方案&#xff1a;從Nginx反向代理到URL重寫技術 引言 在Web應用開發中&#xff0c;URL路徑的安全性往往被忽視&#xff0c;這可能導致網站結構和后端邏輯被攻擊者輕易推斷。對于Flask框架開發的網站&#xff0c;如何隱藏或改變瀏覽…

elementui里的el-tabs的內置樣式修改失效?

1.問題圖 紅框里的是組件的內置樣式&#xff0c;紅框下的是自定義樣式 2.分析 2.1scoped vue模板編譯器在編譯有scoped的stye標簽時&#xff0c;會生成對應的postCSS插件&#xff0c;該插件會給每個scoped標記的style標簽模塊&#xff0c;生成唯一一個對應的 data-v-xxxhash…

大數據測試集群環境部署

Hadoop大數據集群搭建&#xff08;超詳細&#xff09;_hadoop_小飛飛519-GitCode 開源社區 hadoop集群一之虛擬機安裝(mac)_hadoop_皮皮蝦不皮呀-華為開發者空間 hadoop集群二之hadoop安裝_hadoop_皮皮蝦不皮呀-華為開發者空間 虛擬機如何查看gateway | PingCode智庫

Nginx 核心功能筆記

目錄 一、Nginx 簡介 二、核心功能詳解 三、關鍵指令解析 四、性能優化要點 五、常見應用場景 一、Nginx 簡介 定位 高性能的 HTTP/反向代理服務器&#xff0c;同時支持郵件協議代理&#xff08;IMAP/POP3/SMTP&#xff09;。采用 事件驅動、異步非阻塞 架構&#xff0c;…