[英]C++, constructor, destructor
作為一個普遍的開放性問題,可以說為什么有時在代碼中間調用析構函數? 可以調用析構函數的可能場景有哪些? 我想了解以下代碼中的類似效果
class complex
{
private:
double re, im;
protected:
public:
complex()
{
cout << "def const " << endl;
}
complex(double r, double i)
{
cout << "parameterized " << endl;
re = r;
im = i;
}
void setdata(double r, double i)
{
re = r;
im = i;
}
void getdata()
{
cout << "enter real" << endl;
cin >> re;
cout << "enter im" << endl;
cin >> im;
}
//there are 3(?) possible variants of addition...check
//1st
void add(complex c1, complex c2)
{
cout << "in add" << endl;
re = c1.re + c2.re;
im = c1.im + c2.im;
}
//2nd
void add(complex c)
{
cout << "in add" << endl;
re += c.re;
im += c.im;
}
//3rd --- (???)
// complex add(complex c1, complex c2)
// {
// complex retc;
// retc.re = c1.re + c2.re;
// retc.im = c1.im + c2.im;
//
// return retc; //this one is very weird
// }
void display()
{
cout << endl << re << " + " << im << "i" << endl;
}
void mul(complex c1, complex c2)
{
cout << "in mul" << endl;
re = c1.re*c2.re - c1.im*c2.im;
im = c1.re*c2.im + c1.re*c2.im;
}
complex mul(complex c)
{
cout << "in mul" << endl;
complex retc;
retc.re = re*c.re - im*c.im;
retc.im = re*c.im + c.re*im;
return retc;
}
~complex()
{
cout << re << " + " << im << "i" << endl;
cout << "dest" << endl;
}
};
int main()
{
complex c1;
c1.getdata();
complex c2(5, 5);
complex c3;
c3.add(c1, c2); //to store the answer of c1 + c2 we need c3 object
c3.display();
//perform c1 + c2 * c3
complex c4;
c4.add(c1, c2.mul(c3)); //can not use mul(c2, c3) for c2 * c3...why???!
cout << "ans1" << endl;
c4.display();
//or we can also do...
c1.add(c2.mul(c3)); //but this will modify c1
cout << "ans2" << endl;
c1.display();
return 0;
}
以下是輸出
def const
enter real
1
enter im
2
parameterized
def const
in add
1 + 2i
dest
5 + 5i
dest
6 + 7i
def const
in mul
def const
in add
1 + 2i
dest
-5 + 65i
dest
6 + 7i
dest
ans1
-4 + 67i
in mul
def const
in add
-5 + 65i
dest
6 + 7i
dest
ans2
-4 + 67i
-4 + 67i
dest
6 + 7i
dest
5 + 5i
dest
-4 + 67i
dest
知道為什么析構函數為什么會在不知道發生的地方被調用!?
為什么有時在代碼中間調用析構函數?
使用以下方法進行說明:
void mul(complex c1, complex c2)
{
cout << "in mul" << endl;
re = c1.re*c2.re - c1.im*c2.im;
im = c1.re*c2.im + c1.re*c2.im;
}
void add(complex c1, complex c2)
{
cout << "in add" << endl;
re = c1.re + c2.re;
im = c1.im + c2.im;
}
您可以通過以下方式調用它:
c4.add(c1, c2.mul(c3));
add()
和mul()
都按值接收其參數。 當編譯器看到傳遞值的參數時,它將通過復制構造函數創建該參數對象的新版本。 所有類都有一個默認的復制構造函數,該構造函數一個接一個地分配每個字段成員。 此方法的整個版本都使用了這個新版本,並最終將其銷毀。
因此,當您使用c3作為參數在c2中調用mul()
,將從c3創建一個新的復雜對象,並且當mul()
的結尾到達時,該對象將被銷毀。 用c1調用add()
和c2.mul(c3)
的結果也發生了同樣的情況。
如果要避免這種復制(這會花費時間和資源),則應更改函數中傳遞的參數的類型。 具體來說,您可以通過指針或引用傳遞它們。 問題是,這將允許在函數內部對其進行修改:但是在傳遞引用的具體情況下,您可以使用const
對其進行修改,這可以使您兩全其美:您可以有效地傳遞對象而無需修改的可能性。
void mul(const complex &c1, const complex &c2)
{
cout << "in mul" << endl;
re = c1.re*c2.re - c1.im*c2.im;
im = c1.re*c2.im + c1.re*c2.im;
}
void add(const complex &c1, const complex &c2)
{
cout << "in add" << endl;
re = c1.re + c2.re;
im = c1.im + c2.im;
}
考慮到上述方法不會修改被調用的實例,因此它們也可以是const
本身。
void mul(const complex &c1, const complex &c2) const
{
cout << "in mul" << endl;
re = c1.re*c2.re - c1.im*c2.im;
im = c1.re*c2.im + c1.re*c2.im;
}
void add(const complex &c1, const complex &c2) const
{
cout << "in add" << endl;
re = c1.re + c2.re;
im = c1.im + c2.im;
}
同樣,由於這些函數不需要complex的實例,因此它們也可以是獨立的, friend
函數或static
方法。 實際上,這值得另一個答案。
根據經驗,當您只有同一個類的一個參數時(例如在void mul(complex c2)
,則可能是該類的成員。 您將以c1.mul( c2 )
調用它。 當您有兩個參數時,例如在void mul(complex c1, complex c2)
則它是一個獨立的函數(即,您將其作為mul( c1, c2 )
調用,如果希望將它包裝在里面,可以成為朋友您的類或對類的私有成員的訪問權。通常,您創建這些朋友函數是因為您的操作符的左側帶有另一個類(或基元)的對象。另一個問題是獨立函數最好返回一個新的對象而不是修改其參數之一...如您所見,它變得越來越復雜。
無論如何,這些是您的方法應該使用的簽名:
class complex {
public:
// ... more things...
void mul(complex c2);
complex operator*(const complex &c2);
friend complex operator*(int x, const complex &c1);
// ... more things...
};
另外,與其將類與display()
函數綁定到控制台,不如將運算符<<更好地重載,您將能夠在任何流中使用該功能。
希望這可以幫助。
當您在范圍變量的作用域末尾和臨時變量的語句末尾顯式刪除指針時,將調用析構函數。
在你的情況下
c4.add(c1, c2.mul(c3));
您需要計算c2.mul(c3)。 它將創建一個新的復雜類實例。 它會保留以供add執行,並且在調用完成后將銷毀它,因為不再需要它。
首先,請記住,您只需要關注在運行時動態創建的對象的析構函數。 一個簡單的答案是,您需要仔細地驗證代碼並找出代碼中所有動態創建的對象,並確切地檢查何時將超出范圍,即從該對象永不到達的時間/區域。再使用一次,恰好在該時間點,您需要調用該對象的析構函數以清除堆內存。 請記住,析構函數用於釋放/清理內存,以避免內存泄漏和更好地管理進程。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.