目錄
- 1、Delegation Constructor(代理構造)
- 1. What is delegating constructor? (什么是代理構造/委托構造)
- 2. Avoiding recursive calls of target constructors (避免遞歸調用目標ctor)
- 3. 委托構造的好處
- 2、不可變對象和類
- 1、如何讓類成為“不可變類”
- 2、特殊情況:指針成員
- 3、例子
- 4、不可變對象的“不可變”特征在軟件開發中有什么用? 它和thread-safe有什么關系?
- 3、不可變對象和類
- 1、聲明或定義靜態成員
- 2、靜態成員
- 3、實例成員和靜態成員
- 4、C 中static的作用
1、Delegation Constructor(代理構造)
1. What is delegating constructor? (什么是代理構造/委托構造)
代理構造:一個構造函數可以調用另外的構造函數
在代理構造的時候,被委托的要放在委托的構造函數的初始化列表的位置,不能放在在括號里面。
class A{
public: A(): A(0){}A(int i): A(i, 0){}A(int i, int j) {num1=i;num2=j;average=(num1+num2)/2;}
private:int num1;int num2;int average;
};
上面例子中,構造函數的調用次序:
A() ->A(int) ->A(int, int)
在這個過程中,形成了所謂的委托構造量,我們最怕的就是出現環形的委托構造。
2. Avoiding recursive calls of target constructors (避免遞歸調用目標ctor)
遞歸調用:函數調用其本身
遞歸調用實際上就是環形調用。
class A{
public: A(): A(0){}A(int i): A(i, 0){}A(int i, int j): A(){}
private:int num1;int num2;int average;
};
調用次序:
A() -> A(int) ->A(int, int) ->A()
3. 委托構造的好處
讓程序員少寫代碼,使邏輯更加清晰。
執行程序時, 會先執行 一個參數的構造函數, 然后再執行兩個參數的構造函數。
大大減少了代碼量。
2、不可變對象和類
不可變對象:對象創建后,其內容不可改變,除非通過成員拷貝
不可變類:不可變對象所屬的類
1、如何讓類成為“不可變類”
1、所有數據域均設置為“私有”屬性
2、沒有更改器函數
3、也沒有能夠返回可變數據域對象的引用或指針的訪問器
如下:
2、特殊情況:指針成員
如果只有下面兩個條件,是構成不了不可變類的。
1、所有數據域均設置為“私有”屬性
2、沒有更改器函數
如果getter函數返回指向成員的指針,或者getter函數返回成員的引用。那么通過getter函數也能夠修改類成員。
如下:指針指向了類的私有成員,然后我們修改對象的私有數據成員,讓對象不成為不可變類。
所以才要加入第三個條件:沒有能夠返回可變數據域對象的引用或指針的訪問器
3、例子
#include<iostream>
#include<string>
using namespace std;class Date {
private:int year = 2019, month = 1, day = 1;
public:int getYear() { return year; }int getMonth() { return month; }int getDay() { return day; }void setYear(int y) { year = y; }void setMonth(int m) { month = m; }void setDay(int d) { day = d; }Date() = default;Date(int y, int m, int d) :year(y), month(m), day(d) {}std::string toString() {return (std::to_string(year) + '-' + std::to_string(month) + '-' + std::to_string(day));}
};enum class Gender {male,female,
};class Employee {
private:std::string name;Gender gender;Date birthday;
public:void setName(std::string name) { this->name = name; }void setGender(Gender gender) { this->gender = gender; }void setBirthday(Date birthday) { this->birthday = birthday; }std::string getName() { return name; }Gender getGender() { return gender; }Date* getBirthday() { return &birthday; }std::string toString(){return (name +( (gender == Gender::male ? std::string(" male ") : std::string(" female ") )+ birthday.toString()));}//帶參構造函數Employee(std::string name,Gender gender,Date birthday):name{name},gender{gender},birthday{birthday}{}//默認構造函數Employee():Employee("Alan",Gender::male,Date(2000,4,1)){}
};//創建Employee對象,然后修改其生日
int main()
{Employee e;//1:settere.setBirthday(Date(1999,1,1));std::cout << e.toString() << std::endl;//2:gettere.getBirthday()->setYear(1998);std::cout << e.toString() << std::endl;return 0;
}
4、不可變對象的“不可變”特征在軟件開發中有什么用? 它和thread-safe有什么關系?
將一些需要共享和協同開發的內容設為不可變對象可以防止內容被他人修改。起到類似const的作用。
詳細可以觀看這篇文章:
線程安全ThreadSafe
3、不可變對象和類
1、聲明或定義靜態成員
在類定義中,關鍵字 static 聲明 不綁定到類實例的成員( 該成員無需創建實例化對象即可訪問,可以直接用類去訪問)在類的內部聲明
靜態成員的定義是很復雜的。
靜態數據成員定義的規則:
(1) 聲明為“constexpr”類型的靜態數據成員必須 在類中聲明 并初始化。自C++17 起,可不在類外定義
(2) 聲明為==“inline”(C++17 起) 或者 “const int” == 類型的靜態數據成員可以 在類中聲明 并初始化;
(3) 其它須在類外 定義并初始化,且不帶static 關鍵字
靜態數據成員的定義規則復雜,在類外定義,大部分情況下不會出錯
2、靜態成員
靜態數據成員具有靜態存儲期(static storage duration)或者C++11線程存儲期特性。
靜態存儲期
對象的存儲在程序開始時分配,而在程序結束時解回收。
(1) Only one instance of the object exists ( 只存在對象的一個實例)
(2) 靜態存儲器對象未明確初始化時會被自動“零初始化(Zero-Initialization)”
3、實例成員和靜態成員
一旦實例化了Square(創建了Square的對象),每個對象中都有各自的side成員。這個side成員就叫做實例成員。
而numberOfObjects只存在一個,是由所有的Square對象共享的,叫做靜態成員。
class Square {
private:double side;static int numberOfObjects;// ...
public://代理構造,無參構造函數調用有參構造函數Square():Square(1.0){}Square(double side){this->side = side;numberOfObjects++;}// ...
};
//定義靜態數據成員,會被零初始化
int Square::numberOfObjects;
int main() {Square s1{}, s2{5.0};
}
調用一次構造函數,numberOfObjects就會+1,所以numberOfObjects可以統計成員數量
4、C 中static的作用
c語言中static關鍵字用法詳解