C++基礎精講-07

文章目錄

  • 1. const對象
  • 2. 指向對象的指針
  • 3. 對象數組
  • 4. c++中const常見用法總結
    • 4.1 修飾常量
    • 4.2 修飾指針
    • 4.3 修飾函數參數
    • 4.4 修飾函數返回值
    • 4.5 修飾成員函數
    • 4.6 const對象
  • 5. 賦值運算符函數(補充)
    • 5.1 概念
    • 5.2 默認賦值運算符函數局限
    • 5.3 解決辦法


1. const對象

1.概念:在 C++ 中,const 用于定義常量對象,一旦對象被初始化,其值就不能再改變。因為 const 對象只能被創建、撤銷和只讀訪問,寫操作是不允許的。
2.基本使用

#include <iostream>
#include <cstring>namespace myspace1
{using std::endl;using std::cout;using std::cin;using std::string;
}using namespace myspace1;class Person
{
public:Person() :_age(0), _name(new char[strlen("張三") + 1]){cout << "無參構造" << endl;strcpy(_name, "張三");}Person(int age,  const char* name) :_age(age), _name(new char[strlen(name) + 1]){cout << "有參構造" << endl;strcpy(_name, name);}void setAge(int age){_age = age;}void print(){cout << "age=" << _age << endl;cout << "name=" << _name << endl;}//const成員函數,不能修改對象的數據成員void print() const{cout << "age=" << _age << endl;cout << "name=" << _name << endl;}~Person(){delete[] _name;cout << "析構函數" << endl;}
private:int _age;char* _name;
};int main(void)
{//普通對象Person p1(1,"張大");p1.print();p1.setAge(10);p1.print();//const 對象只能被創建、撤銷和只讀訪問,寫操作是不允許的const Person p2(2, "張二");//p2.setAge(20)   //不允許//p2.print();     //不允許p2.print();        //調用的是void print() constreturn 0;
}

在這里插入圖片描述

3.總結
const對象與const成員函數的規則:
(1)當類中有const成員函數和非const成員函數重載時,const對象會調用const成員函數,非const對象會調用非const成員函數;
(2)當類中只有一個const成員函數時,無論const對象還是非const對象都可以調用這個版本;
(3)當類中只有一個非const成員函數時,const對象就不能調用非const版本。

建議:如果一個成員函數中確定不會修改數據成員,就把它定義為const成員函數。

2. 指向對象的指針

int main(void)
{//在棧上開辟空間Person p1(1, "一號");Person* p2 = &p1;  //指向p1的指針;Person* p3 = nullptr;  //空指針;//在堆上開辟空間Person* p4 = new Person(2, "二號");delete p4;p4 = nullptr;Person* p5 = new Person();p5->setAge(20);  p5->print();(*p5).setAge(30);(*p5).print();delete p5;p5 = nullptr;return 0;
}

3. 對象數組

#include <iostream>
#include <cstring>namespace myspace1
{using std::endl;using std::cout;using std::cin;using std::string;
}using namespace myspace1;class Person
{
public:Person() :_age(0), _name(new char[strlen("張三") + 1]){cout << "無參構造" << endl;strcpy(_name, "張三");}Person(int age,  const char* name) :_age(age), _name(new char[strlen(name) + 1]){cout << "有參構造" << endl;strcpy(_name, name);}void setAge(int age){_age = age;}void print(){cout << "age=" << _age << endl;cout << "name=" << _name << endl;}//const成員函數,不能修改對象的數據成員void print() const{cout << "age=" << _age << endl;cout << "name=" << _name << endl;}~Person(){delete[] _name;cout << "析構函數" << endl;}
public:int _age;char* _name;
};int main(void)
{// 方式一:使用無參/默認構造函數創建對象數組cout << "使用默認構造函數創建對象數組:" << endl;Person p1[3];for (int i = 0; i < 3; i++) {p1[i].print();}// 方式二:使用有參構造函數初始化對象數組cout << "使用有參構造函數初始化對象數組:" << endl;Person p2[3] = {Person(20, "李四"),Person(21, "王五"),Person(22, "趙六")};for (int i = 0; i < 3; ++i) {p2[i].print();}// 方式三:動態分配對象數組cout << "動態分配對象數組:" << endl;Person* p3 = new Person[2];p3[0].setAge(25);strcpy(p3[0]._name, "孫七");p3[1].setAge(26);strcpy(p3[1]._name, "周八");for (int i = 0; i < 2; ++i) {p3[i].print();}// 釋放動態分配的內存delete[] p3;return 0;
}

4. c++中const常見用法總結

4.1 修飾常量

//只有讀權限,沒有寫權限
const int a = 10;    //==int const a=10;
//a = 20;  不可以修改

4.2 修飾指針

int main(void)
{int a = 10;int b = 20;//1.指向常量的指針const int* p1 = &a;  //==int const* p1 = &a;//*p1 = 100;   不可以為通過指針修改a的值;p1 = &b;  //可以修改指針p1的指向//2.常量指針;可以通過指針修改變量的值,但是指針的指向不可以變;int* const p2 = &a;*p2 = 20;//p2 = &b;  錯誤//3.指向常量的常量指針:指針的指向和所指向的值都不能改變const int* const p3 = &a;// *p3 = 20; // 錯誤,不能通過指針修改所指向的值// p3 = &b; // 錯誤,不能改變指針的指向return 0;
}

4.3 修飾函數參數

const 用于修飾函數參數時,能夠保證在函數內部不會修改該參數的值。

void fun(const int a)
{//a = 100;   錯誤cout << "a=" <<a<< endl;
}int main(void)
{int a = 10;fun(a);return 0;
}

4.4 修飾函數返回值

const 修飾函數返回值時,表明返回值是一個常量,不能被修改。

//const 修飾函數返回值時,表明返回值是一個常量,不能被修改。
int const fun()
{int a = 10;return a;           
}int main(void)
{//fun() = 100;  錯誤,不可以修改return 0;
}

4.5 修飾成員函數

const 修飾類的成員函數時,表明該成員函數不會修改對象的狀態

class MyClass {
private:int _value;
public:MyClass(int val) : _value(val) {}// 常量成員函數int getValue() const {// value = 20; // 錯誤,不能在常量成員函數中修改成員變量return _value;}
};

4.6 const對象

const 對象是指那些一經創建,其狀態(即成員變量的值)就不能被修改的對象

class MyClass {
public:int _value;MyClass(int v) : _value(v) {}
};int main() {const MyClass obj(10);// obj.value = 20; // 錯誤,不能修改 const 對象的成員變量cout << "Value: " << obj._value << endl;return 0;
}

5. 賦值運算符函數(補充)

5.1 概念

Point pt1(1, 2), pt2(3, 4);
pt1 = pt2;//賦值操作

在執行 pt1 = pt2; 該語句時, pt1 與 pt2 都存在,所以不存在對象的構造,這要與 Point pt2 =pt1; 語句區分開,這是不同的。所以當 = 作用于對象時,需要調用的是賦值運算符函數
格式:

類名& operator=(const 類名 &)
class Point {
private:int _ix;int _iy;
public:Point(int x = 0, int y = 0) : _ix(x), _iy(y) {}//默認賦值運算符重載函數Point& operator=(const Point& rhs){_ix = rhs._ix;_iy = rhs._iy;return *this;}void print() const {cout << "(" << _ix << ", " << _iy << ")" <<endl;}
};int main() {Point p1(1, 2);Point p2(3, 4);p2 = p1;p2.print();return 0;
}

5.2 默認賦值運算符函數局限

(1)當類中包含指針數據成員且該指針指向堆上分配的內存時,默認的賦值運算符函數(編譯器自動生成的)就無法滿足需求,這可能會導致淺拷貝問題,進而引發內存泄漏或懸空指針等錯誤。
(2)默認的賦值運算符執行的是淺拷貝,也就是只復制指針的值,而不復制指針所指向的內存。這會造成兩個對象的指針成員指向同一塊內存,當其中一個對象被銷毀時,它會釋放這塊內存,而另一個對象的指針就會變成懸空指針。另外,如果兩個對象都嘗試釋放同一塊內存,會導致重復釋放,引發未定義行為。

class Person
{
public://構造函數Person(const int* age) :_age(new int(*age)){cout << "構造函數" << endl;}//打印函數void print()const{cout << "age=" << *_age << endl;}//析構函數~Person(){delete _age;cout << "析構函數" << endl;}
private:int* _age;
};int main(void)
{int age1 = 20;int age2 = 30;Person p1(&age1);p1.print();Person p2(&age2);p2.print();p2 = p1;return 0;
}

問題分析:
當執行 p2 = p1; 時,會調用編譯器自動生成的默認賦值運算符。默認賦值運算符執行的是淺拷貝,即只復制指針的值,而不復制指針所指向的內存。這會導致 p1 和 p2 的 _age 指針指向同一塊內存。由于淺拷貝,當 p2 對象被銷毀時,會釋放 _age 所指向的內存。此時,p1 的 _age 指針就會變成懸空指針。當 p1 對象被銷毀時,再次釋放同一塊內存,會導致重復釋放,引發未定義行為。

5.3 解決辦法

為了解決淺拷貝的問題,需要自定義賦值運算符函數,實現深拷貝。深拷貝會為新對象分配新的內存,并將原對象的數據復制到新的內存中。

class Person
{
public://構造函數Person(const int* age) :_age(new int(*age)){cout << "構造函數" << endl;}//打印函數void print()const{cout << "age=" << *_age << endl;}//自定義賦值運算符函數Person& operator=(const Person& rhs){//自我賦值檢查if (this != &rhs) {//釋放當前_age空間;delete _age;_age = nullptr;_age = new int(*rhs._age);}return *this;}//析構函數~Person(){delete _age;cout << "析構函數" << endl;}
private:int* _age;
};int main(void)
{int age1 = 20;int age2 = 30;Person p1(&age1);p1.print();Person p2(&age2);p2.print();p2 = p1;return 0;
}

若你有自行定義某些特殊成員函數,編譯器會為類自動生成以下 6 個默認函數:

  1. 默認構造函數
  2. 析構函數
  3. 拷貝構造函數
  4. 拷貝賦值運算符
  5. 移動構造函數(C++11 及以后)
  6. 移動賦值運算符(C++11 及以后)

注意拷貝構造函數、賦值運算符函數、析構函數,如果需要手動定義其中的一個,那么另外兩個也需要手動定義。 三合成原則

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

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

相關文章

軟件測試之接口測試用例設計

1.接口測試用例設計簡介 我們對系統的需求分析完成之后&#xff0c;即可設計對應的接口測試用例&#xff0c;然后用接口測試用例進行接口測試。接口測試用例的設計也需要用到黑盒測試方法&#xff0c;其與功能測試用例設計的方法類似&#xff0c;接口測試用例設計中還需要增加…

(2)VTK C++開發示例 --- 繪制多面錐體

文章目錄 1. 概述2. CMake鏈接VTK3. main.cpp文件4. 演示效果 更多精彩內容&#x1f449;內容導航 &#x1f448;&#x1f449;VTK開發 &#x1f448; 1. 概述 VTK C開發示例程序&#xff1b; 使用C 和VTK繪制一個多面錐體。 環境說明系統ubuntu22.04、windows11cmake3.22、3.2…

公司內部自建知識共享的方式分類、詳細步驟及表格總結,分為開源(對外公開)和閉源(僅限內部),以及公共(全員可訪問)和內部(特定團隊/項目組)四個維度

以下是公司內部自建知識共享的方式分類、詳細步驟及表格總結&#xff0c;分為開源&#xff08;對外公開&#xff09;和閉源&#xff08;僅限內部&#xff09;&#xff0c;以及公共&#xff08;全員可訪問&#xff09;和內部&#xff08;特定團隊/項目組&#xff09;四個維度&am…

DeepSeek使用001:Word中配置DeepSeek AI的V3和R1模型

文章目錄 Word中配置DeepSeek大模型1、勾選開發工具2、信任中心設置3、添加DeepSeek-V3模型4、獲取API KEY5、添加DeepSeek-R1模型6、新建組7、測試使用 Word中配置DeepSeek大模型 1、勾選開發工具 打開【選項】 選擇【自定義功能區】 2、信任中心設置 打開【信任中心】&…

Spark-SQL核心編程語言

利用IDEA開發spark-SQL 創建spark-SQL測試代碼 自定義函數UDF 自定義聚合函數UDAF 強類型的 Dataset 和弱類型的 DataFrame 都提供了相關的聚合函數&#xff0c; 如 count()&#xff0c; countDistinct()&#xff0c;avg()&#xff0c;max()&#xff0c;min()。除此之外&…

從圖像“看出動作”

&#x1f4d8; 第一部分&#xff1a;運動估計&#xff08;Motion Estimation&#xff09; &#x1f9e0; 什么是運動估計&#xff1f; 簡單說&#xff1a; &#x1f449; 給你一段視頻&#xff0c;計算機要“看懂”里面什么東西動了、往哪動了、有多快。 比如&#xff1a; 一…

Spring Boot 使用 SMB 協議

2025/4/14 向全棧工程師邁進&#xff01; 一、詳述SMB協議 SMB&#xff08;Server Message Block&#xff09;協議是一個網絡文件共享協議&#xff0c;它使得計算機可以在網絡中共享文件、打印機以及其他資源。SMB 主要用于 Windows 操作系統&#xff0c;但也有其他平臺&#…

Spring編程式事務(本地事務)

使用 TransactionTemplate等類和 API 手動管理事務&#xff0c;控制事務的新建、提交、回滾等過程 方式一&#xff1a;使用 TransactionTemplate&#xff08;推薦方式&#xff09; Service public class OrderService {private final TransactionTemplate transactionTemplat…

itext7 html2pdf 將html文本轉為pdf

1、將html轉為pdf需求分析 經常會看到爬蟲有這樣的需求&#xff0c;將某一個網站上的數據&#xff0c;獲取到了以后&#xff0c;進行分析&#xff0c;然后將需要的數據進行存儲&#xff0c;也有將html轉為pdf進行存儲&#xff0c;作為原始存檔&#xff0c;當然這里看具體的需求…

企業級低代碼平臺的架構范式轉型研究

在快速迭代的數字時代&#xff0c;低代碼平臺如同一股清流&#xff0c;悄然成為開發者們的新寵。 它利用直觀易用的拖拽式界面和豐富的預制組件&#xff0c;將應用程序的開發過程簡化到了前所未有的程度。通過封裝復雜的編程邏輯和提供強大的集成能力&#xff0c;低代碼平臺讓…

C++ | STL之list詳解:雙向鏈表的靈活操作與高效實踐

引言 std::list 是C STL中基于雙向鏈表實現的順序容器&#xff0c;擅長高效插入和刪除操作&#xff0c;尤其適用于頻繁修改中間元素的場景。與std::vector不同&#xff0c;std::list的內存非連續&#xff0c;但提供了穩定的迭代器和靈活的元素管理。本文將全面解析std::list的…

AI運算服務器工控機特點與應用

AI運算服務器工控機是專門針對工業環境設計的計算設備&#xff0c;結合了傳統工控機&#xff08;工業控制計算機&#xff09;的可靠性與AI服務器的強大算力&#xff0c;廣泛應用于智能制造、邊緣計算、機器視覺、自動化控制等領域。以下是其核心特點、應用場景及選型建議&#…

25/4/9 算法筆記 DBGAN+強化學習+遷移學習實現青光眼圖像去模糊1

整體實驗介紹 實驗主要是結合DBGAN對抗網絡強化學習增強遷移學習增強實現青光眼圖像去模糊。今天則是先完成了DBGAN板塊模型的訓練。 實驗背景介紹 青光眼的主要特征有&#xff1a; 視盤形態與杯盤比CDR&#xff1a;青光眼患者主要表現為視杯擴大&#xff0c;盤沿變窄。 視…

智能復盤自動化系統搭建指南—基于DeepSeek API與Apple日歷的整合實踐

一、系統架構設計 本方案通過iOS快捷指令實現日歷數據與AI分析的自動化交互&#xff0c;核心流程包含&#xff1a; 日歷事件管理 創建每日循環的"AI復盤"日歷事項實現當日備注信息的動態更新 數據處理模塊時間日志標準化處理多維度數據特征提取 AI交互層對接DeepSeek…

01 位運算

12days 章節結構 00 算法前導課-編程基礎&#xff08;自學的視頻&#xff09; 01 位運算的奇巧淫技 02 查找與排序&#xff08;上&#xff09; 03 數組、查找與排序(下) 04 多維數組與矩陣 05 字符串專題 06 基本數學問題 06 遞歸、DFS、剪枝、回溯等問題 07 貪心策…

HDFS Full Block Report超限導致性能下降的原因分析

文章目錄 前言發現問題失敗的為什么是FBR塊匯報頻率的變化為什么FBR會反復失敗HDFS性能下降導致Yarn負載變高的形式化分析理解線程理解IO Wait理解HDFS性能下降導致Yarn負載和使用率增高 引用 前言 我們的Yarn Cluster主要用來運行一批由Airflow定時調度的Spark Job&#xff0…

【Kubernetes基礎--Pod深入理解】--查閱筆記2

深入理解Pod 為什么要有個Pod1. 容器協作與資源共享2. 簡化調度和資源管理3. 設計模式支持 Pod 基本用法Pod 容器共享 VolumePod 的配置管理ConfigMap 概述創建 ConfigMap 資源對象在 Pod 中使用 ConfigMap使用 ConfigMap 的限制條件 為什么要有個Pod Pod 的引入并非技術冗余&…

Margin和Padding在WPF和CSS中的不同

CSS和WPF中 margin 與 padding 在方向上的規定基本一致&#xff0c;但在使用場景和一些細節上有所不同。 CSS - 方向規定&#xff1a; margin 和 padding 屬性可以分別指定上、右、下、左四個方向的值。例如 margin:10px 20px 30px 40px; 表示上外邊距為10px、右外邊距為20…

gravity`(控制 View 內部內容的對齊方式)

文章目錄 **1. 常用取值****示例** **2. layout_gravity&#xff08;控制 View 在父容器中的對齊方式&#xff09;****常用取值****示例** **3. gravity vs layout_gravity 對比****4. 注意事項****5. 總結** 作用對象&#xff1a;當前 View 的內部內容&#xff08;如 TextView…

Go:使用共享變量實現并發

競態 在串行程序中&#xff0c;步驟執行順序由程序邏輯決定&#xff1b;而在有多個 goroutine 的并發程序中&#xff0c;不同 goroutine 的事件先后順序不確定&#xff0c;若無法確定兩個事件先后&#xff0c;它們就是并發的。若一個函數在并發調用時能正確工作&#xff0c;稱…