嵌入式C++開發詳解(三)

丫就是熊個貓貓發表於2017-02-09

建構函式與解構函式(一)

一、建構函式

(1)建構函式

  ·建構函式是特殊的成員函式

  ·建立類型別的新物件,系統自動會呼叫建構函式

  ·建構函式是為了保證物件的每個資料成員都被正確初始化

PS:1.當沒有建構函式的時候,系統會自動生成無參的建構函式

    我們一般自己加上無參建構函式,不做任何處理

  2.全域性物件的建構函式先於Main函式執行

1.建構函式特點

·函式名與類名完全相同

·不能定義構造建構函式的型別(返回型別),也不能使用void,通常情況下構造

  函式應宣告為公有函式,否則它不能像其他成員函式那樣被顯式地呼叫

·建構函式被宣告為私有有特殊的用途

·成員物件的建構函式先於本身物件的建構函式呼叫

2.預設建構函式

·不帶引數的建構函式

·如果程式未宣告,則系統自動生成一個預設建構函式

建構函式程式碼示例:

Test.h
#ifndef _TEST_H_
#define _TEST_H_
class Test
{
public:
    Test(int x,int y,int z);
private:
    int x_;
    int y_;
    int z_;
};
 
#endif
Test.cpp
#include "Test.h"
#include <iostream>
 
using namespace std;
 
Test::Test(int x, int y, int z)
{
    cout << "init Test!" << endl;
    x_ = x;
    y_ = y;
    z_ = z;
}
main.c
#include <iostream>
#include "Test.h"
 
using namespace std;
 
int main()
{
    Test t(1,2,3);
    return 0;
}

執行結果:

 

3.建構函式的過載

程式碼示例:

Test.h
#ifndef _TEST_H_
#define _TEST_H_
class Test
{
public:
    Test();//預設的無參建構函式
    Test(int x,int y,int z);
private:
    int x_;
    int y_;
    int z_;
};
 
#endif
Test.cpp
#include "Test.h"
#include <iostream>
 
using namespace std;
Test::Test()
{
    cout << "init Test2!\n" << endl;
}
Test::Test(int x, int y, int z)
{
    cout << "init Test!" << endl;
    x_ = x;
    y_ = y;
    z_ = z;
}
main.c
#include <iostream>
#include "Test.h"
 
using namespace std;
 
int main()
{
    Test t1;
    Test t(1,2,3);
    return 0;
}

執行結果:

 

4.建構函式與new運算子

程式碼示例:

Test.h
#ifndef _TEST_H_
#define _TEST_H_
class Test
{
public:
    Test();//預設的無參建構函式
    Test(int x,int y,int z);
private:
    int x_;
    int y_;
    int z_;
};
 
#endif
Test.cpp
#include "Test.h"
#include <iostream>
 
using namespace std;
Test::Test()
{
    cout << "init Test2!" << endl;
}
Test::Test(int x, int y, int z)
{
     cout << "init Test!" << endl;
     x_ = x;
     y_ = y;
     z_ = z;
}
main.c
#include <iostream>
#include "Test.h"
 
using namespace std;
 
int main()
{
     Test t1;
     Test t(1,2,3);
     Test *p = new Test(3,4,5);
     Test array[3] = { Test(7, 8, 9) };
     return 0;
}


執行結果:

 

5.全域性物件的建構函式先於Main函式

程式碼示例:

Test.h:
#ifndef _TEST_H_
#define _TEST_H_
class Test
{
public:
     Test(int x,int y,int z);
     ~Test();
private:
     int x_;
     int y_;
     int z_;
};
 
#endif
Test.cpp:
#include "Test.h"
#include <iostream>
 
using namespace std;
Test::Test(int x, int y, int z)
{
     x_ = x;
     y_ = y;
     z_ = z;
 
     cout << "init Test!" << x_ << endl;
}
Test::~Test()
{
     cout << "destory Test!" << x_ << endl;
}
main.c
#include <iostream>
#include "Test.h"
 
using namespace std;
Test t3;
int main()
{
     cout << "main function!" <<endl;
     Test t1(1,2,3);
     Test t(4,5,6);
     Test *p = new Test(7,8,9);
     delete p;
     return 0;
}

執行結果:

 

(二)轉換建構函式

 ·單個引數的建構函式

 ·將其它型別轉換為類型別

 ·類的建構函式只有一個引數是非常危險的,因為編譯器可以使用這種構

   造函式把引數的型別隱式轉換為類型別

1.初始化與賦值的區別

程式碼示例:

Test.h:
#ifndef _TEST_H_
#define _TEST_H_
class Test
{
public:
	Test(int x);
	Test();
	~Test();
private:
	int x_;

};

#endif
Test.cpp:
#include "Test.h"
#include <iostream>

using namespace std;
Test::Test()
{
	cout << "default Test!" << endl;
}
Test::Test(int x)
{
	x_ = x;

	cout << "init Test!" << x_ << endl;
}
Test::~Test()
{
	cout << "destory Test!" << x_ << endl;
}
msin.c
#include <iostream>
#include "Test.h"

using namespace std;

int main()
{	Test t = 10;   //初始化
	t = 20;     //呼叫轉換建構函式構建了一個臨時物件
     //將臨時物件賦值給物件
	return 0;
}


執行結果:


2.轉換建構函式

int main()
{    Test t = 10;   //Test t(10) 初始化
     t = 20;      //賦值(運算子)
      //呼叫轉換建構函式構建了一個臨時物件Test(20)
      //將臨時物件賦值給t物件
      //臨時物件析構
     return 0;
}


部分程式碼示例:

Test& Test :: operator = (const Test &other)
{
     if (this == &other)
     {
        return *this;
     }
     this->x_ = other.x_;
 
     cout << "operator = !" << endl;
     
     return * this;
}
 

執行結果:

 


3.explicit關鍵字  (使轉換建構函式不生效)

 ·只提供給類的建構函式使用的關鍵字

 ·編譯器不會把宣告為explicit的建構函式用於隱式轉換,它只能在程式程式碼中顯示建立物件。

4.建構函式初始化列表

 ·推薦在建構函式初始化列表中進行初始化

 ·建構函式的執行分為兩個階段(初始化段、普通計算段)

 ·const成員的初始化只能在建構函式初始化列表中進行

 ·引用成員的初始化也只能在建構函式初始化列表中進行

 ·物件成員(物件所對應的類沒有預設建構函式)的初始化,也只能在構造函

   數初始化列表中進行

程式碼示例:

class Object
{
public:
    Object(int num = 0) : num_(num),kNum_(num),count(num),obj(num)
    {
        cout << “Object” << num_ << “...” << endl;
    }
    ~Object()
    {
       cout << “~Object” << num_ << “...” << endl;
    }

void DisplayKNum():num_(num),kNum_(num),count(num)
{
    cout << “KNum = ” << kNum << endl;
}
private:
     int num_;
     int kNum_;
     const int count;
     object obj;//成員物件
};


5.列舉物件適用於所有物件

程式碼舉例:

Test.h:
#ifndef _TEST_H_
#define _TEST_H_
class Test
{
public:
     enum Result
     {
         success = 1,
         failed = -1
      };
      Test(int x);
      Test();
      ~Test();
      Test& operator = (const Test &other);
private:
      int x_;
      const int num_;
};
 
#endif
Main.c
#include <iostream>
#include "Test.h"
 
using namespace std;
 
int main()
{
    cout << Test::success << endl;
    return 0;
}


(三)拷貝建構函式

·功能:使用一個已經存在的物件來初始化一個新的同一型別的物件

·宣告:只有一個引數並且引數為該類物件的引用

·如果類中沒有說明拷貝建構函式,則系統自動生成一個預設複製建構函式,

 作為該類的公有成員

1.程式碼示例:

Test.h:
#ifndef _TEST_H_
#define _TEST_H_
class Test
{
public:
     enum Result
     {
         success = 1,
         failed = -1
     };
     Test(int x);
     Test();
     ~Test();
     Test(const Test &other);
     Test& operator = (const Test &other);
private:
    int x_;
    const int num_;
};
 
#endif
Test.cpp:
#include "Test.h"
#include <iostream>
 
using namespace std;
Test::Test() :num_(0)
{
    cout << "default Test!" << endl;
}
Test::Test(int x) : x_(x),num_(x)
{
    x_ = x;
 
    cout << "init Test!" << x_ << endl;
}
Test::Test(const Test &other) : x_(other.x_), num_(2)
{
    cout << "copy Function!" << endl;
}
Test::~Test()
{
     cout << "destory Test!" << x_ << endl;
}
 
Test& Test :: operator = (const Test &other)
{
    if (this == &other)
    {
        return *this;
    }
    this->x_ = other.x_;
 
    cout << "operator = !" << endl;
 
    return *this;
}
Main.c
#include <iostream>
#include "Test.h"
 
using namespace std;
 
int main()
{
     Test t1(5);
     Test t2(t1);
 
     return 0;
}

執行結果:

 

2.拷貝建構函式的呼叫情況

 ·用已有物件初始化物件會呼叫拷貝建構函式

 ·當函式的形參是類的物件,呼叫函式時,進行形參與實參結合時使用

 ·當函式的返回值是類物件,函式執行完成返回撥用者時使用

3.深拷貝與淺拷貝

簡單理解:如果一個類擁有資源,當這個類的物件發生複製過程的時候,資源重新分配,這個過程就是深拷貝,反之,沒有重新分配資源,就是淺拷貝

·類中有指標成員時,一定要進行深拷貝

·=運算子必須實現深拷貝

·對於獨一無二的物件禁止拷貝,將拷貝建構函式私有化。

程式碼示例:

String.h:
#ifndef _STRING_H_
#define _STRING_H_
 
class String
{
public:
String();
String(char *str);
~String();
String(const String& other);
String& operator = (const String& other);
void Display();
private:
char *str_;
};
 
#endif
String.cpp:
#include "String.h"
#include <iostream>
 
using namespace std;
 
String::String()
{
str_ = new char('\0');
cout << "default constrictor string!" << endl;
}
 
String::String(char *str)
{
cout << "constructor String" << endl;
 
int len = strlen(str) + 1;
str_ = new char(len);
memset(str_, 0, len);
strcpy(str_, str);
}
 
void String::Display()
{
cout << str_ << endl;
}
 
String :: ~String()
{
cout << "destory String!" << endl;
 
delete[] str_;
}
 
String::String(const String& other)
{
int len = strlen(other.str_) + 1;
 
str_ = new char(len);
memset(str_, 0, len);
strcpy(str_, other.str_);
}
 
String& String :: operator=(const String& other)
{
if (this == &other)
{
return *this;
}
int len = strlen(other.str_) + 1;
delete[] str_;
str_ = new char[len];
memset(str_, 0, len);
strcpy(str_, other.str_);
}
 
Main.cpp:
#include "String.h"
#include <iostream>
 
using namespace std;
 
int main()
{
String s1("hello");
s1.Display();
 
String s2(s1);
s2.Display();
return 0;
}


 

執行結果:


4.空類預設生成的成員

class Empty{};

Empty();   //預設建構函式

Empty(const Empty&);   //預設拷貝建構函式

~Empty();     //預設解構函式

Empty& operator = (const Empty&);  //預設賦值運算子

Empty* operator&();   //取地址運算子

const Empty* operator&() const; //取地址運算子const

 

二、解構函式

(一)解構函式

·函式名和類名相似(前面多了一個字元“~”)

·沒有返回型別

·沒有引數

·解構函式不能被過載

·如果沒有定義解構函式,編譯器會自動生成一個預設解構函式,其式如下:

  類名::~預設析構名()

  {

  }

  預設解構函式是一個空函式

·預設解構函式是一個空函式

程式碼示例:

Test.h:
#ifndef _TEST_H_
#define _TEST_H_
class Test
{
public:
     Test(int x,int y,int z);
     ~Test();
private:
     int x_;
     int y_;
     int z_;
};
 
#endif
Test.cpp:
#include "Test.h"
#include <iostream>
 
using namespace std;
Test::Test(int x, int y, int z)
{
     x_ = x;
     y_ = y;
     z_ = z;
 
     cout << "init Test!" << x_ << endl;
}
Test::~Test()
{
     cout << "destory Test!" << x_ << endl;
}
main.c
#include <iostream>
#include "Test.h"
 
using namespace std;
 
int main()
{
     Test t1(1,2,3);
     Test t(4,5,6);
     Test *p = new Test(7,8,9);
     delete p;
     return 0;
}

執行結果:

 

在區域性物件時,建構函式呼叫順序與解構函式正好相反。

1.解構函式與陣列

2.解構函式與delete運算子

  解構函式在變數釋放時嗎,才呼叫,所以只有delete指標之後,才會呼叫解構函式

程式碼示例:

Test.h:
#ifndef _TEST_H_
#define _TEST_H_
class Test
{
public:
     Test(int x,int y,int z);
     Test();
     ~Test();
private:
     int x_;
     int y_;
     int z_;
};
 
#endif
Test.cpp:
#include "Test.h"
#include <iostream>
 
using namespace std;
Test::Test()
{
     cout << "default Test!" << endl;
}
Test::Test(int x, int y, int z)
{
     x_ = x;
     y_ = y;
     z_ = z;
 
     cout << "init Test!" << x_ << endl;
}
Test::~Test()
{
     cout << "destory Test!" << x_ << endl;
}
main.c
#include <iostream>
#include "Test.h"
 
using namespace std;
 
int main()
{
    Test *p = new Test[3];
    delete[] p;
    return 0;
}


3.解構函式顯式呼叫

 

相關文章