[英]C++: Implicit call of constructor from another constructor
我很難理解我正在處理的項目中的隱式構造函數調用。
有兩個接口:InterfaceA和InterfaceB。
然后,有兩個實現類:ImplementA和ImplementB,它們是從各自的接口派生的。 盡管接口和類非常相似,但任何時候都沒有共同的祖先。
第三類Component可用於初始化任何Implement類。
所以我們有這樣的事情:
class InterfaceA
{
public:
InterfaceA(){}
virtual ~InterfaceA(){}
// Some functions
}
class InterfaceB
{
public:
InterfaceB(){}
virtual ~InterfaceB(){}
// Some functions
}
class ImplementA : public InterfaceA
{
public:
ImplementA(Component& input);
ImplementA(Component* input);
ImplementA(const ImplementA& impl);
ImplementA(const ImplementB& impl);
ImplementA();
~ImplementA(void);
private:
Component* m_component;
bool some_boolean;
}
class ImplementB : public InterfaceB
{
public:
ImplementB(Component& input);
ImplementB(const ImplementA& impl);
ImplementB(const ImplementB& impl);
ImplementB();
~ImplementB(void);
private:
Component* m_component;
}
然后,我們有一個函數返回一個指向Component的指針:
Component* foo()
{
Component* result = new Component();
...
return result;
}
最后,在代碼中的某個地方,我們得到以下返回:
return new ImplementB(foo());
運行時,上面的代碼行執行foo(),然后執行ImplementA(Component * input),然后執行ImplementB(const ImplementA&impl)-這使我非常困惑。
1.為什么還要編譯? 編譯器不應該抱怨這種類型的參數沒有有效的構造函數(當我在有問題的調用中更改某些內容時,它就會這樣做)。 順便說一下,我正在使用Visual Studio 2012。
2.我知道,當構造函數獲取指向對象的指針作為參數時,它首先調用該參數的副本構造函數。 因此,如果我忽略了沒有合適的構造函數的事實-它不應該使用Component的復制構造函數而不是ImplementA嗎? ImplementA似乎與ImplementB絕對沒有聯系(除了它們具有相似的結構)。
我想念什么? 在這種情況下,什么可能導致此行為?
這就是您擁有太多令人困惑的構造函數的結果。 我也強烈懷疑您到處都有內存泄漏。
請注意, ImplementA
具有構造函數ImplementA(Component&)
和構造函數ImplementA(Component*)
。 但是ImplementB
僅具有ImplementB(Component&)
。 這很混亂。
因此,當您執行new ImplementB(foo())
,沒有構造函數直接接受Component*
。 編譯器會尋找其他選項。 具體來說,它正在尋找一種將參數Component*
轉換為ImplementB
某些構造函數所接受的方法。
C ++有一些稱為用戶定義的轉換的東西。 您可以定義轉換運算符和轉換構造函數 ,以定義類型之間的新隱式類型轉換。 事情是這樣的:任何具有單個參數的構造函數都是轉換構造函數,除非它被顯explicit
標記。 (這可能是C ++中的一個設計錯誤。但是我們堅持下去。)
因此, ImplementA(Component*)
定義了從Component*
到ImplementA
的隱式轉換。 還有一個ImplementB(const ImplementA&)
構造函數,可以接受一個臨時的ImplementA
。 因此,編譯器使用此構造函數,使用轉換的構造函數創建臨時結構,最終結果是您看到的執行。
解決方案是使所有這些構造函數都是explicit
,並定義更少,更少混淆的構造函數。 並使用智能指針擺脫內存泄漏。
return new ImplementB(foo());
運行時,上面的代碼行執行foo(),然后執行ImplementA(Component * input),然后執行ImplementB(const ImplementA&impl)-這使我非常困惑。
對foo
的調用返回Component*
。 當我們檢查ImplementB
的構造函數時,我們發現
ImplementB(Component& input);
ImplementB(const ImplementA& impl);
ImplementB(const ImplementB& impl);
因此,這些都不接受Component*
。
但是“幸運的”選項之一是可以從指針構造的ImplementA
。
傳遞參數時,允許一個 “用戶定義的轉換”。
foo
返回一個Component*
。
ImplementB
沒有接受Component*
的構造函數。 但是,它有一個接受const ImplementA&
的const ImplementA&
構造const ImplementA&
。
現在, Component*
可通過接受Component*
的后者的構造函數隱式轉換為ImplementA
。 因此,它將進行轉換,並且通過const引用將所得的ImplementA
臨時變量傳遞給ImplementB
的適當構造函數。
如果您重視理智,則可能不希望在代碼附近的任何地方進行任何隱式轉換。 要停止用戶定義類型的隱式轉換,請將所有單參數構造函數explicit
。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.