1. 程式人生 > >物件的構造與析構(二)

物件的構造與析構(二)

目錄

  • 1. 解構函式
  • 2. 物件的構造與析構順序
    • 多個物件之間
    • 單個物件內部
  • 3. const物件與const成員函式
    • const物件
    • const成員函式
  • 4. 成員函式、成員變數與物件的關係
  • 5. 程式碼實戰——陣列類IntArray
    • IntArray.h
    • IntArray.cpp
    • IntArray測試

1. 解構函式

  • C++的類中可以定義一個特殊的清理函式,叫做解構函式,語法規則為~ClassName()
  • 解構函式沒有引數,也沒有返回值型別宣告
  • 解構函式在物件銷燬時自動被呼叫
  • 當類中自定義了建構函式,並且建構函式中使用了系統資源(如:堆空間、檔案開啟,等),則需要自定義解構函式

2. 物件的構造與析構順序

多個物件之間

多個物件構造時:

  • 棧物件的構造順序依賴於程式的執行流
  • 堆物件的構造順序依賴於new的使用順序
  • 全域性物件的構造順序是不確定的,不同的編譯器可能使用不同的規則

多個物件析構時:

  • 棧物件和全域性物件的析構順序與構造順序相反
  • 堆物件的析構發生取決於delete的使用順序

單個物件內部

單個物件建立時,物件內部建構函式的呼叫順序為:

  • 先呼叫父類的建構函式
  • 再呼叫成員變數的建構函式,呼叫順序與宣告順序相同
  • 最後呼叫類自身的建構函式

單個物件內部的析構順序與構造順序相反。

3. const物件與const成員函式

const物件

  • 由const關鍵字修飾的物件為只讀物件
  • 只讀物件的成員變數不允許被改變
  • 只讀屬性只在編譯階段有效,執行時無效

const成員函式

const成員函式的定義如下所示,需要注意的是,函式宣告和函式定義都必須帶const關鍵字。

Type ClassName :: func(Type para) const

關於const成員函式的使用,有下面幾條規則:

  • const物件只能呼叫const成員函式
  • const成員函式只能呼叫const成員函式
  • const成員函式不能直接修改成員變數的值
#include <stdio.h>

class Test
{
    int mi;
public:
    Test(int i);
    void setMi(int i) const;
    int getMi() const;
    void printMi();
};

Test::Test(int i)
{
    mi = i;
}

void Test::setMi(int i) const
{
    mi = i;  //Error,const成員函式中不能直接修改成員變數的值
}

int Test::getMi() const
{
    return mi;
}

void Test::printMi()
{
    printf("printMi(): mi = %d\n", mi);
}

int main()
{
    const Test t1(1);

    t1.getMi();    //OK,const物件呼叫const成員函式
    t1.printMi();  //Error,const物件呼叫普通成員函式

    return 0;
}

4. 成員函式、成員變數與物件的關係

從面向物件的角度,物件由屬性(成員變數)和方法(成員函式)構成;
從程式執行的角度,物件由資料和函式構成,資料位於棧、堆或全域性資料區,函式位於程式碼段。

  • 每一個物件都擁有自己獨立的屬性(成員變數)
  • 所有的物件共享類的方法(成員函式)
  • 方法能夠直接訪問物件的屬性
  • 方法中的隱藏引數this指標用於值代當前物件
#include <stdio.h>

class Test
{
    int mi;
public:
    int mj;
    Test(int i);
    Test(const Test &t);
    int getMi();
    void print();
};

Test::Test(int i)
{
    mi = i;
}

Test::Test(const Test &t)
{
    mi = t.mi;  //成員函式可以直接訪問對應類物件的成員變數
}

int Test::getMi()
{
    return mi;
}

void Test::print()
{
    printf("this = %p\n", this);  //每個成員函式中隱藏了一個this指標,用於指向當前物件
}

int main()
{
    Test t1(1);
    Test t2(2);
    Test t3(3);

    printf("t1.getMi() = %d\n", t1.getMi());
    printf("&t1 = %p\n", &t1);
    t1.print();

    printf("t2.getMi() = %d\n", t2.getMi());
    printf("&t2 = %p\n", &t2);
    t2.print();

    printf("t3.getMi() = %d\n", t3.getMi());
    printf("&t3 = %p\n", &t3);
    t3.print();

    return 0;
}

5. 程式碼實戰——陣列類IntArray

IntArray.h

#ifndef _INTARRAY_H_
#define _INTARRAY_H_

class IntArray
{
private:
    int m_length;
    int *m_pointer;
public:
    IntArray(int len);
    IntArray(const IntArray &obj);
    int length();
    bool get(int index, int &value);
    bool set(int index ,int value);
    ~IntArray();
};

#endif

IntArray.cpp

#include "IntArray.h"

IntArray::IntArray(int len)
{
    m_pointer = new int[len];

    for(int i=0; i<len; i++)
    {
        m_pointer[i] = 0;
    }

    m_length = len;
}

IntArray::IntArray(const IntArray &obj)
{
    m_length = obj.m_length;

    m_pointer = new int[obj.m_length];

    for(int i = 0; i < obj.m_length; i++)
    {
        m_pointer[i] = obj.m_pointer[i];
    }
}

int IntArray::length()
{
    return m_length;
}

bool IntArray::get(int index, int &value)
{
    bool ret = (0 <= index) && (index < length());

    if( ret )
    {
        value = m_pointer[index];
    }

    return ret;
}

bool IntArray::set(int index, int value)
{
    bool ret = (0 <= index) && (index < length());

    if( ret )
    {
        m_pointer[index] = value;
    }

    return ret;
}

IntArray::~IntArray()
{
    delete[] m_pointer;
}

IntArray測試

#include "IntArray.h"
#include <stdio.h>

int main()
{
    IntArray a(5);

    for(int i = 0; i < a.length(); i++)
    {
        a.set(i, i + 1);
    }

    for(int i = 0; i < a.length(); i++)
    {
        int value = 0;

        if( a.get(i, value) )
        {
            printf("a[%d] = %d\n", i, value);
        }
    }

    IntArray b = a;

    for(int i = 0; i < b.length(); i++)
    {
        int value = 0;

        if( b.get(i, value) )
        {
            printf("b[%d] = %d\n", i, value);
        }
    }

    return 0;
}

相關推薦

物件構造

目錄 1. 解構函式 2. 物件的構造與析構順序 多個物件之間 單個物件內部 3. const物件與const成員函式 const物件 con

C++學習筆記——構造

建構函式:在建立物件時執行的函式 特性: 1.建構函式與類名相同 2.建構函式無返回型別(必須沒有) 3.建立物件時被呼叫(類似於初始化) 4.建構函式可以有引數(建立時直接傳入) 形如:A(); 以下是一個建構函式的例子: #include <s

python裡的魔法方法1構造

魔法方法——構造與析構 1、python程式設計的魔法方法: (1)魔法方法總是被雙下劃線包圍,例如__init__; (2)魔法方法是面向物件的python的一切。 2、__new__(class[,…])魔法方法 主要用來重新修改和對於實際類()裡面所帶引數的修改,__new__ 方法主要任務是

6.1 物件構造Object Costruction and Destruction

一般而言,constructor和destructor的安插如你所預期那樣: //C++ pseudo { Point point; //point.Point::Point(); 一般會被安插在這裡 ... //point.Point::~Point(); 一般會被安插在這裡 }

DLL中物件構造

動態連結庫中全域性變數的構造與析構: 背景:你在當前main函式中通過LoadLibrary來載入MFCLibraryDll.dll 1 MFCLibraryDll中的全域性變數A b的建立與析構會自動執行: 1)LoadLibrary執行時第一時間建立LoadLibrary中的全域

SGISTL原始碼閱讀四 物件構造

SGISTL原始碼閱讀四 物件的構造與析構 前言 前面我們提到,SGISTL將空間配置和物件的構造分開操作了,前面的文章我們對空間配置已經做了描述,下面我們來看一下如何構造和析構物件。 深入原始碼 construc //接受一個指標和一個初值 template <c

包含物件成員的類的構造順序

首先,我們來看一段程式碼: #include<iostream> using namespace std; class A { public: A() { cout << "A's constructor." << endl;

Java靜態分派動態分派

xiang oid main isp 準備 center 使用 name 編譯過程 方法調用並不等於方法執行,方法調用階段唯一的任務就是確定被調用方法的版本(即調用哪一個方法),暫時還不涉及方法內部的具體運行過程。 在程序運行時,進行方法調用是最普遍、最頻繁的操作,但是Cl

面向對象中的繼承、封裝、構造函數

再次 釋放內存 創建 訪問 完整性 struct 事務 完整 參數 構造函數:是一種特殊的方法。主要用來在創建對象時初始化對象,即為對象成員變量賦值初始值,總與new運算符一起使用在創建對象的 語句中。兩根下劃線開頭,construct 作用:為

ELJSTL學習——JSTL技術

功能 裝包 str 常用標簽 bsp jsp頁面 reac and 返回 1.JSTL概述 JSTL(JSP Standard Tag Library),JSP標準標簽庫,可以嵌入在jsp頁面中使用標簽的形式完成業務邏輯等功能。 jstl出現的目的同el一樣也是要代替j

C++繼承中的構造

pause cout default sys class bject iostream pub efault #include <iostream> #include <string> using namespace std; class O

數據結構算法--棧隊列

break col color 一個 大小 amp 頂上 const 試題 棧和隊列 棧和隊列都是比較常用的數據結構。棧的應用非常的廣泛,比如說,遞歸函數的實現就是借助於棧保存相關的數據。操作系統中每個線程也會使用棧來保存函數調用涉及到的一些參數和其他變量等。棧最大的一個特

Swift 構造

前言 pri logs 允許 arr 管理 必須 直接 生命周期 前言 與 OC 一樣,Swift 中也存在構造和析構過程。不同的是,OC 中的構造方法和析構方法只是普通的方法,而 Swift 中構造器和析構器是一種特殊的結構。 1、構造器 在 Swift 中,類或者

C之有符號無符號

C語言 有符號數 無符號數 我們在 C 語言中經常會見到 unsigned 關鍵字,那麽這是什麽意思呢?在計算機內,數據類型分為有符號和無符號兩種類型。它的最高位用於標識數據的符號:如果最高位為 1,表明這個數為負數;如果是0的則表明這個數為正數。那麽我們就來做個試驗驗證下,代碼如

VIVADO FIR濾波器設計仿真

put tps ilo 用法 ilog ril [ ] 技術 仿真 VIVADO FIR濾波器設計與仿真(二) 在VIVADO FIR濾波器設計與仿真(一)中產生了兩路正弦信號,頻率分別為4MHz和5MHz,今天要進行FIR濾波器設計,在進行濾波器設計之前,需要對濾波器的參

數據結構算法

port timer類 mage pass func 代碼執行 atm 數據結構與算法 設置 python內置類型性能分析 timeit模塊 class timeit.Timer(stmt="pass",setup=‘pass‘,time=<timer functio

認識設計Serverless

平臺 三方 服務 函數 style bubuko spa ron pan 一、設計Serverless的功能模塊   第一節講了Serverless一些概念與特性,廢話居多,概念的東西了解過後要有設計與構思,才能學到精髓,一個Serverless平臺的形成,涉及到很多模塊的

TCP/IP協議HTTP協議

動向 沒有 代理 serve 相互 基本 而且 網絡連接 正式 TCP/IP協議是傳輸層協議,主要解決數據如何在網絡中傳輸,而HTTP是應用層協議,主要解決如何包裝數據。 1、TCP連接 手機能夠使用聯網功能是因為手機底層實現了TCP/IP協議,可以使手機終端通過無線網絡

關於類繼承的構造調用分析

fff 調用父類 派生類的構造函數 臨時 臨時對象 構造函數 back 基類 原因分析   總體結論:派生類的構造函數在創建對象時調用,調用順序如下:        1.調用虛基類的構造函數(若有多個虛基類,調用順序為繼承的順序。);        2.調用基類的構造函

Java常用的八種排序演算法程式碼實現:歸併排序法、快速排序法

注:這裡給出的程式碼方案都是通過遞迴完成的 --- 歸併排序(Merge Sort):   分而治之,遞迴實現   如果需要排序一個數組,我們先把陣列從中間分成前後兩部分,然後對前後兩部分進行分別排序,再將排好序的數組合並在一起,這樣整個陣列就有序了   歸併排序是穩定的排序演算法,時間