簡體   English   中英

C ++:從另一個構造函數隱式調用構造函數

[英]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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM