原文鏈接:https://www.zhoubotong.site/post/87.html 之所以寫這篇文章,是覺得裡面有些細節如果不註意,很容易出錯或踩坑,網上有很多教程對這塊的描述部分存在錯誤。希望下麵的介紹能給大家帶來幫助。 大家知道當我們需要初始化類中的成員變數時,除了可以直接在構造函數裡面 ...
原文鏈接:https://www.zhoubotong.site/post/87.html
之所以寫這篇文章,是覺得裡面有些細節如果不註意,很容易出錯或踩坑,網上有很多教程對這塊的描述部分存在錯誤。希望下麵的介紹能給大家帶來幫助。
大家知道當我們需要初始化類中的成員變數時,除了可以直接在構造函數裡面進行直接賦值,還可以使用初始化列表的方式來對成員變數進行初始化。
提到這裡,順便說下什麼是構造函數初始化列表。
C++初始化列表
語法
Contructor(type1 var1, type2 var2): m_var1(var1), m_var2(var2)
{
}
參數
屬性 | 描述 |
---|---|
type1 | 形參 var1 的類型。 |
var1 | 形參 var1。 |
type2 | 形參 var2 的類型。 |
var2 | 形參 var2。 |
m_var1 | 成員變數 m_var1。 |
m_var2 | 成員變數 m_var2。 |
說明
我們使用初始化列表的方式,用形參 var1 初始化了成員變數 m_var1,用形參 var2 初始化了成員變數 m_var2。舉個例子:
#include <iostream>
using namespace std;
class Student {
private:
char *m_name;
int m_age;
float m_score;
public:
Student(char *name, int age, float score);
void show();
};
// 採用初始化列表
Student::Student(char *name, int age, float score)
: m_name(name), m_age(age), m_score(score) {
// TODO
}
void Student::show() {
cout << m_name << " age is " << m_age << "score is " << m_score << endl;
}
int main() {
Student stu((char *)"鳩摩智", 28, 5);
stu.show();
Student *pstu =
new Student((char *)"慕容復", 27, 86); // 使用指針對象 new 實例化
pstu->show();
return 0;
}
上面的例子定義構造函數時並沒有在函數體中對成員變數賦值,而是在函數首部與函數體之間添加了一個冒號:,後面緊跟m_name(name), m_age(age), m_score(score)語句,
可以理解成相當於函數體內部的m_name = name; m_age = age; m_score = score;也是賦值的意思。
註意:使用構造函數初始化列表並沒有效率上的優勢,僅僅是書寫方便,當成員變數較多時這種寫法非常簡潔。
下麵重點說下需要註意的地方:
初始化列表可以用於全部成員變數,也可以只用於部分成員變數。什麼意思?比如我們只對 m_name 使用初始化列表,其他成員變數還是=賦值:
// 採用初始化列表
Student::Student(char *name, int age, float score)
: m_name(name) { // 只用於部分成員變數
m_age = age;
m_score = score;
}
輸出結果是一樣的。 註意!註意!註意!,成員變數的初始化順序與初始化列表中列出的變數的順序無關,它只與成員變數在類中聲明的順序有關。
請大家仔細看下麵的代碼:
#include <iostream>
using namespace std;
class Student {
private:
int m_age;
float m_score;
public:
Student(float s);
void show();
};
Student::Student(float s) : m_score(s), m_age(m_score) {} //註意這裡:我們將m_score放在了m_age的前面,看起來是先給m_score賦值,再給m_age賦值(m_age=m_score),其實不是的
void Student::show() { cout << m_age << ", " << m_score << endl; }
int main() {
Student stu(99);
stu.show();
return 0;
}
結論
所以成員變數的賦值順序由它們在類中的聲明順序決定,在 上面的Student 類中,我們先聲明的 m_age,再聲明的 m_score,
給 m_age 賦值時,m_score 還未被初始化,所以輸出的m_age的值是預設類型的0;給 m_age 賦值完成後才給m_score 賦值,此時 m_score 的值才是99。
如果大家對上面理解了,我們再看下麵的代碼,大家可以猜下輸出啥?
#include <iostream>
using namespace std;
class Student {
private:
int m_age;
float m_score;
public:
Student(float s);
void show();
};
Student::Student(float s) : m_score(s), m_age(m_score) {
m_age = m_score;
m_score = s;
}
void Student::show() { cout << m_age << ", " << m_score << endl; }
int main() {
Student stu(99);
stu.show();
return 0;
}
輸出:99, 99,大家請細品!寫到最後再提下:構造函數初始化列表還有一個很重要的作用,那就是初始化 const 成員變數。
網上很多教程說初始化 const 成員變數的唯一方法就是使用初始化列表。這是錯誤的,描述的不夠嚴謹,為什麼這樣說,我們來看網上很多教程的例子:
#include <iostream>
using namespace std;
class Student {
public:
Student(string name, int age) {
m_name = name;
m_age = age;
}
void show();
private:
const string m_name;
int m_age;
};
void Student::show() { cout << m_name << ", " << m_age << endl; }
int main() {
Student stu("鳩摩智", 28);
stu.show();
Student stu1("慕容復", 27);
stushow();
return 0;
}
輸出:
於是網上很多教程說只能使用初始化列表的方式,來進行初始化,現在,按照網上的說法修改程式如下:
#include <iostream>
using namespace std;
class Student {
public:
Student(string name, int age) : m_name(name), m_age(age) {}
void show();
private:
const string m_name;
int m_age;
};
void Student::show() { cout << m_name << ", " << m_age << endl; }
int main() {
Student stu("鳩摩智", 28);
stu.show();
Student stu1("慕容復", 27);
stushow();
return 0;
}
這次在構造函數上面,使用了初始化列表的方式,初始化了 const 成員變數,這次程式沒有報錯,因此,const 成員變數只可以使用初始化列表的方式進行初始化( 誤人)。
這個描述是錯誤的,並不是 const 成員變數只能使用初始化列表。在構造函數裡面初始化賦值是沒有任何問題的。
針對上面的問題我們來改下代碼。註意這裡只是改變了m_name的數據類型為指針型。
#include <iostream>
using namespace std;
class Student {
public:
Student(char *name, int age) { // 使用構造方法初始化賦值
m_name = name;
m_age = age;
}
void show();
private:
const char *m_name; // 註意這裡是指針變數的常量
int m_age;
};
void Student::show() { cout << m_name << ", " << m_age << endl; }
int main() {
Student stu((char *)"鳩摩智", 28);
stu.show();
Student stu1((char *)"慕容復", 27);
stushow();
return 0;
}
無論從事什麼行業,只要做好兩件事就夠了,一個是你的專業、一個是你的人品,專業決定了你的存在,人品決定了你的人脈,剩下的就是堅持,用善良專業和真誠贏取更多的信任。所以類中對於 const 修飾,既可以使用初始化列表的方式賦值,也可以使用構造函數的方式賦值。