C++中的幾種特殊成員函數
構造函數
C++在編譯器會給我們默認創建一個缺省的構造方法: 如下代碼:
class Father {
public:
string name = "father";
int age = 45;
void print() {
cout << "name:" << name << " age:" << age << endl;
}
};
class Son :public Father {
public:
string sex = "male";
};
void extendsTest::mainTest()
{
Son son;
son.print();
};
運行結果:name:father age:45
可以看到雖然我們沒有明確聲明構造方法,但是依然可以調用無參構造方法。這就是因為 編譯器自動給我們創建了一個無參構造方法 、
如果類定義了自己的構造方法后(包括無參和有殘),編譯器就不會給我們創建了 ,看下面代碼:
class Father {
public:
Father() {
cout << "Father:" << name << endl;
}
string name = "father";
int age = 45;
void print() {
cout << "name:" << name << " age:" << age << endl;
}
};
class Son :public Father {
public:
Son(){
cout << "Son:" << name << endl;
}
string sex = "male";
};
void extendsTest::mainTest()
{
Son son;
son.print();
};
打印結果:
Father:father
Son:father
name:father age:45
從上面代碼也可以看出C++編譯器會默認優先調用父類的構造方法,再調用子類的構造方法,
這點和java中是有區別的,java會從子類開始依次調用父類的構造方法,然后回溯子類的構造方法
所以為了保證對象的順利創建,需要保證父類的構造方法是有效的。 如下代碼:
class Father {
public:
Father(string _name):name(_name){
cout << "Father:" << name << endl;
}
string name = "father";
int age = 45;
};
此時父類中創建了一個有參構造方法,前面說過,此時編譯器不會創建默認的無參構造方法,則需要保證在其子類中有初始化父類的操作:即調用父類有參構造方法。 如下代碼:
class Son :public Father {
public:
Son(string name):Father(name) {
cout << "Son:" << name << endl;
}
string sex = "male";
};
void extendsTest::mainTest()
{
Son son1("myName");
};
結果:
Father:myName
Son:myName
析構函數
析構函數用來釋放當前對象使用到的內存空間,當對象跳出其作用域范圍后就會執行析構函數( 除非是有智能指針出現循環引用的情況,無法釋放,導致泄露 )。 C++中析構函數和構造函數相反,會 優先調用子類的析構函數再調用父類的析構函數 。 如下代碼:
class Father {
public:
~Father() {
cout << "~Father"<< endl;
}
string name = "father";
int age = 45;
};
class Son :public Father {
public:
~Son() {
cout << "~Son" << endl;
}
string sex = "male";
};
void extendsTest::mainTest()
{
Son son;
};
運行結果:
~Son
~Father
拷貝構造
C++中拷貝構造函數格式:
- 格式1 :帶const參數 Complex(const Complex& c) { … } 表示以常量對象作為參數
- 格式2 :不帶const參數 Complex(Complex& c) { … } 表示以非常量作為參數進行拷貝 如下代碼:
class Complex {
public:
double real, imag;
Complex(double _real, double _imag):
real(_real),imag(_imag)
{
cout << "real:" << real << " imag:" << imag << endl;
}
void print() {
cout << "real:" << real << " imag:" << imag << endl;
}
Complex(Complex& c) {
real = c.real+1; imag = c.imag+1;
}
};
void extendsTest::mainTest()
{
Complex c1(1.0, 2.0);
Complex c2(c1);
c2.print();
};
打印結果:
real:1 imag:2
real:2 imag:3
拷貝構造函數和構造方法類似, C++編譯器會給我們提供默認的拷貝構造函數 。 將上面代碼的拷貝構造函數刪除后:
class Complex {
public:
double real, imag;
Complex(double _real, double _imag):
real(_real),imag(_imag)
{
cout << "real:" << real << " imag:" << imag << endl;
}
void print() {
cout << "real:" << real << " imag:" << imag << endl;
}
};
void extendsTest::mainTest()
{
Complex c1(1.0, 2.0);
Complex c2(c1);
c2.print();
};
依然可以執行拷貝構造,此時c2使用了默認拷貝構造函數進行賦值。
拷貝構造的幾種調用形式:
-
1.當用一個對象去初始化同類的另一個對象時
Complex c2(c1); Complex c2 = c1;
這兩天語句是等價的。但是要 注意此時Complex c2 = c1是一個初始化語句,并非一個賦值語句。賦值語句是一個已經初始化后的變量 。 如下:
Complex c1, c2; c1 = c2 ; c1=c2;
賦值語句不會觸發拷貝構造 。
-
2.當對象作為一個函數形參時,此時也會觸發對象的拷貝構造
class Complex { public: double real, imag; Complex(double _real, double _imag): real(_real),imag(_imag) { cout << "real:" << real << " imag:" << imag << endl; } Complex(Complex& c) { real = c.real+1; imag = c.imag+1; cout << "complex copy" << endl; } }; void func(Complex c) { cout << "real:" << c.real << " imag:" << c.imag << endl; } void extendsTest::mainTest() { Complex c(1.0,2.0); func(c); }; 運行結果: real:1 imag:2 complex copy real:2 imag:3
可以看到運行結果觸發了Complex的拷貝構造 以對象作為函數的形參,在函數被調用時,生成的形參要用復制構造函數初始化,這會帶來時間上的開銷。 如果用對象的引用而不是對象作為形參,就沒有這個問題了 。
void func(Complex& c) { cout << "real:" << c.real << " imag:" << c.imag << endl; }
但是以引用作為形參有一定的風險,因為這種情況下如果形參的值發生改變,實參的值也會跟著改變。 最好的方法就是將函數形參聲明為const類型的引用 。
void func(const Complex& c) { cout << "real:" << c.real << " imag:" << c.imag << endl; }
-
3.對象作為函數返回值返回時,也會觸發拷貝構造。
Complex func() { Complex c(1.0, 2.0); return c; } void extendsTest::mainTest() { cout << func().real << endl; }; 結果: real:1 imag:2 complex copy 2
可以看到此時func函數中的return c處會觸發一次拷貝構造,并將拷貝后的對象返回。 這點通過函數hack過程也可以看出來:此處call方法執行的是拷貝構造方法
-
JAVA
+關注
關注
19文章
2974瀏覽量
104981 -
C++
+關注
關注
22文章
2114瀏覽量
73793 -
面向對象編程
+關注
關注
0文章
22瀏覽量
1835
發布評論請先 登錄
相關推薦
評論