日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程语言 > c/c++ >内容正文

c/c++

C++中的构造函数

發布時間:2025/4/5 c/c++ 27 豆豆
生活随笔 收集整理的這篇文章主要介紹了 C++中的构造函数 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

文章目錄

    • 1 構造函數的基本概念
      • 1.1 構造函數的作用
      • 1.2 構造函數的特點
      • 1.3 構造函數的種類
    • 2 默認構造函數
      • 2.1 合成的默認構造函數
      • 2.2 手動定義的默認構造函數
    • 3 自定義的重載構造函數
      • 3.1 自定義的重載構造函數
      • 3.2 創建對象的幾種方式
      • 3.3 手工調用構造函數
    • 4 拷貝構造函數
      • 4.1 合成的拷貝構造函數
      • 4.2 手動定義的拷貝構造函數
      • 4.3 拷貝構造函數的調用時機
      • 4.4 繼承關系中的拷貝構造函數
    • 5 賦值構造函數
      • 5.1 合成的賦值構造函數
      • 5.2 自定義的賦值構造函數
    • 6 在已經申請的空間上調用構造函數

1 構造函數的基本概念

1.1 構造函數的作用

構造函數的作用:

  • 在創建一個新的對象時,自動調用的函數,用來進行“初始化”工作。
  • 對這個對象內部的數據成員進行初始化。

1.2 構造函數的特點

構造函數的特點:

  • 自動調用(在創建新對象時,自動調用)。
  • 構造函數的函數名,和類名相同。
  • 構造函數沒有返回類型。
  • 可以有多個構造函數(即函數重載形式)。

1.3 構造函數的種類

構造函數的種類:

  • 默認構造函數
  • 自定義的構造函數
  • 拷貝構造函數
  • 賦值構造函數

2 默認構造函數

沒有參數的構造函數,稱為默認構造函數。

2.1 合成的默認構造函數

當類中沒有定義任何構造函數時,編譯器默認提供一個無參構造函數,并且其函數體為空:

  • 如果數據成員使用了“類內初始值”,就使用這個值來初始化數據成員。【C++11】
  • 否則,就使用默認初始化(實際上,不做任何初始化)

注意:
只要手動定義了任何一個構造函數(包括拷貝構造函數),編譯器就不會生成“合成的默認構造函數”。一般情況下,都應該定義自己的構造函數,不要使用“合成的默認構造函數”,僅當數據成員全部使用了“類內初始值”,才宜使用“合成的默認構造函數”

#include <iostream> #include <Windows.h> #include <string>using namespace std;// 定義一個“人類” class Human { public: //公有的,對外的void eat(); //方法, “成員函數”void sleep();void play();void work();string getName();int getAge();int getSalary();private:string name;int age = 18;int salary; };void Human::eat() {cout << "吃炸雞,喝啤酒!" << endl; }void Human::sleep() {cout << "我正在睡覺!" << endl; }void Human::play() {cout << "我在唱歌! " << endl; }void Human::work() {cout << "我在工作..." << endl; }string Human::getName() {return name; }int Human::getAge() {return age; }int Human::getSalary() {return salary; }int main(void) {Human h1; // 使用合成的默認初始化構造函數cout << "年齡: " << h1.getAge() << endl; //使用了類內初始值cout << "薪資:" << h1.getSalary() << endl; //沒有類內初始值system("pause");return 0; }

2.2 手動定義的默認構造函數

手動定義的默認構造函數,常稱為“默認構造函數”。

Human::Human() {name = "無名氏";age = 18;salary = 30000; }int main(void) {Human h1; // 使用自定義的默認構造函數cout << "姓名:" << h1.getName() << endl;cout << "年齡: " << h1.getAge() << endl; cout << "薪資:" << h1.getSalary() << endl; system("pause");return 0; }

說明: 如果某數據成員使用類內初始值,同時又在構造函數中進行了初始化,那么以構造函數中的初始化為準。相當于構造函數中的初始化,會覆蓋對應的類內初始值。


3 自定義的重載構造函數

3.1 自定義的重載構造函數

自定義的重載構造函數比較簡單,示例代碼如下:

Human::Human() {name = "無名氏";age = 18;salary = 30000; }Human::Human(int age, int salary) {cout << "調用自定義的構造函數" << endl; this->age = age; //this是一個特殊的指針,指向這個對象本身this->salary = salary;name = "無名"; }int main(void) {Human h1(25, 35000); // 使用自定義的默認構造函數cout << "姓名:" << h1.getName() << endl;cout << "年齡: " << h1.getAge() << endl; cout << "薪資:" << h1.getSalary() << endl; system("pause");return 0; }

3.2 創建對象的幾種方式

#include <stdio.h>class Test { public:Test() { printf("Test()\n");}Test(int v) { printf("Test(int v), v = %d\n", v);} };int main() {Test t; // 第一種:調用 Test()Test t1(1); // 第二種:調用 Test(int v)Test t2 = 2; // 第三種:調用 Test(int v)Test t3 = Test(); // 第4種:調用Test()int i(100);printf("i = %d\n", i);return 0; }

3.3 手工調用構造函數

一般情況下,構造函數在對象定義時被自動調用;但是在一些特殊情況下,我們需要手工調用構造函數。

創建對象數組就需要手工調用構造函數:

#include <stdio.h>class Test { private:int m_value; public:Test() { printf("Test()\n");m_value = 0;}Test(int v) { printf("Test(int v), v = %d\n", v);m_value = v;}int getValue(){return m_value;} };int main() {Test ta[3] = {Test(), Test(1), Test(2)}; for(int i=0; i<3; i++){printf("ta[%d].getValue() = %d\n", i , ta[i].getValue());}Test t = Test(100);printf("t.getValue() = %d\n", t.getValue());return 0; }

4 拷貝構造函數

4.1 合成的拷貝構造函數

當類中沒有定義拷貝構造函數時,編譯器默認提供也給拷貝構造函數,簡單的進行成員變量的復制。編譯器默認提供的拷貝構造函數也叫合成的拷貝構造函數,合成的拷貝構造函數使用“淺拷貝”。

拷貝構造函數的意義:

  • 兼容C語言的初始化方式。
  • 初始化行為能夠符合預期的邏輯。

拷貝構造函數分為淺拷貝和深拷貝:

  • 淺拷貝:拷貝后對象的物理狀態相同。
  • 深拷貝:拷貝后對象的邏輯狀態相同。

當對象中有成員指代了系統的資源,我么需要進行深拷貝:

  • 成員指向了動態內存空間。
  • 成員打開了外存中的文件。
  • 成員使用了系統中的網絡端口。

編譯器提供的拷貝構造函數只進行淺拷貝!

4.2 手動定義的拷貝構造函數

一般性原則:自定義拷貝構造函數,必然要實現深拷貝!

4.3 拷貝構造函數的調用時機

什么時候調用拷貝構造函數?

  • 調用函數時,實參是對象,形參不是引用類型。如果函數的形參是引用類型,就不會調用拷貝構造函數。
  • 函數的返回類型是類,而且不是引用類型。
  • 對象數組的初始化列表中,使用對象。
  • void test(Human man) {cout << man.getSalary() << endl; }void test2(Human &man) { //不會調用拷貝構造函數,此時沒有沒有構造新的對象cout << man.getSalary() << endl; }Human test3(Human &man) {return man; }Human& test4(Human &man) {return man; }int main(void) {Human h1(25, 35000); // 調用默認構造函數Human h2(h1); // 調用拷貝構造函數Human h3 = h1; // 調用拷貝構造函數test(h1); // 調用拷貝構造函數test2(h1); // 不會調用拷貝構造函數test3(h1); // 創建一個臨時對象,接收test3函數的返回值,調用1次拷貝構造函數Human h4 = test3(h1); // 僅調用1次拷貝構造函數,返回的值直接作為h4的拷貝構造函數的參數test4(h1); // 因為返回的是引用類型,所以不會創建臨時對象,不會調用拷貝構造函數Human men[] = { h1, h2, h3 }; //調用3次拷貝構造函數system("pause");return 0; }

    4.4 繼承關系中的拷貝構造函數

    假設B繼承自A,如下代碼:

    B b1; B b2(b1); // 先調用A類的構造函數,再調用B類的拷貝構造函數

    5 賦值構造函數

    5.1 合成的賦值構造函數

    如果沒有定義賦值構造函數,編譯器會自動定義“合成的賦值構造函數”,與其他合成的構造函數相同,是“淺拷貝”(又稱為“位拷貝”)。

    5.2 自定義的賦值構造函數

    簡要的賦值構造函數代碼如下:

    Human& Human::operator=(const Human &man) {cout << "調用" << __FUNCTION__ << endl;if (this == &man) {return *this; //檢測是不是對自己賦值:比如 h1 = h1;}// 如果有必要,需要先釋放自己的資源(動態內存)//delete[] addr;//addr = new char[ADDR_LEN];// 深拷貝strcpy_s(addr, ADDR_LEN, other.addr);// 處理其他數據成員name = man.name;age = man.age;salary = man.salary;// 返回該對象本身的引用, 以便做鏈式連續處理,比如 a = b = c;return *this; }

    6 在已經申請的空間上調用構造函數

    這真是一個騷操作,很多情況下我們需要為對象預先分配空間,但是如果對象沒有默認的構造函數就會很尷尬。我們可以通過malloc分配空間,然后在需要的時間再在這片空間上調用指定的構造函數。示例代碼如下:

    #include <iostream> #include <vector> #include <cstdlib>using namespace std;class Test39 { private:int age; public:Test39(){cout << "Test39()" << endl;}~Test39(){cout << "~Test39()" << endl;} };void test39() {Test39* p = (Test39*)malloc(sizeof(Test39));new (p) Test39();p->~Test39(); }

    不得不說C++真的是騷,真的足夠強大,真的讓我學不會!越學不會我越喜歡,不信搞不定C++。


    參考資料:

  • C/C++從入門到精通-高級程序員之路【奇牛學院】
  • C++深度解析教程
  • 《新程序員》:云原生和全面數字化實踐50位技術專家共同創作,文字、視頻、音頻交互閱讀

    總結

    以上是生活随笔為你收集整理的C++中的构造函数的全部內容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。