簡體   English   中英

C2440 static_cast無法從基類轉換為派生類

[英]C2440 static_cast cannot convert from base class to derived class

我試圖理解為什么使用指針從基類強制轉換為派生類的編譯效果很好,但是使用非指針對象進行強制轉換會產生錯誤C2440。

下面有一個基類ThreadedMessage ,它由類GPSMessage繼承。

struct ThreadedMessage
{
  ThreadedMessage()
    : m_Type(0), m_ID(0)
  { }

  ThreadedMessage(uint Type, uint ID = 0) :
    m_Type(Type), m_ID(ID)
  { }

  uint m_Type;
  uint m_ID;
};    

struct GPSMessage : public ThreadedMessage
{
  GPSMessage()
    : ThreadedMessage()
  { }

  GPSMessage(double lat, double lon)
    : ThreadedMessage(1), m_lat(lat), m_lon(lon)
  { }

  double m_lat;
  double m_lon;
};

myFunction我嘗試從基類myFunction轉換為派生類。

void myFunction(const ThreadedMessage& msg)
{
  const GPSMessage* message = static_cast<const GPSMessage*>(&msg); // Compiles fine
  const GPSMessage message1 = static_cast<const GPSMessage>(msg);   // Error C2440
}

myFunction()的調用如下所示:

GPSMessage msg(21.123, 12.321);
myFunction(msg);

當我編譯時,指針的轉換可以正常編譯,但是非指針的轉換失敗,並出現以下錯誤:

錯誤C2440:“ static_cast”:無法從“ const ThreadedMessage”轉換為“ const GPSMessage”沒有構造函數可以采用源類型,或者構造函數重載解析度不明確

為什么我不能使用非指針變量將基類轉換為派生類?

編譯器為MS VS 2008 C ++。

是的,我看過其他類似的SO問題,但我閱讀的問題似乎無法回答我的問題。

這兩個角色具有不同的含義。

第一個演員:

const GPSMessage* message = static_cast<const GPSMessage*>(&msg); // Compiles fine

這意味着msg實際上是GPSMessage (或派生的)對象。 您要求編譯器將msg作為GPSMessage威脅。 不會創建新對象, message將指向msg 如果msg實際上不是GPSMessage (或派生的),則此GPSMessage Undefined Behavior。

順便說一句,下面的演員表具有相同的含義(鑄造參考):

const GPSMessage& message = static_cast<const GPSMessage&>(msg); // same meaning, which results in a reference instead of a pointer

關於第二個演員表:

const GPSMessage message1 = static_cast<const GPSMessage>(msg);   // Error C2440

這意味着您將創建一個對象, message1 msg message1 您應該提供一種使這種轉換成為可能的方法。 例如,您應該為GPSMessage創建一個具有ThreadedMessage參數的構造函數:

struct GPSMessage {
    GPSMessage(const ThreadedMessage &); // needed constructor
};

或創建ThreadedMessageGPSMessage的轉換運算符:

struct ThreadedMessage {
    operator GPSMessage(); // conversion operator
};

在函數中,編譯器僅知道msg是對ThreadedMessage的引用,而不知道在函數內部作為參數實際傳遞了什么。

想想如果傳遞對實際 ThreadedMessage對象的引用會發生什么情況? 還是從其他繼承的類對另一個對象的引用?

要從ThreadedMessage對象轉換為GPSMessage對象,需要進行轉換,並且這種轉換是不可能的( ThreadedMessage類沒有轉換運算符,而GPSMessage沒有合適的構造函數)。

唯一的解決方案是將指針或引用轉換為另一個指針或引用。 就像您在指針示例中所做的那樣,或通過例如

const GPSMessage& message1 = static_cast<const GPSMessage&>(msg);

如果您確實要GPSMessage轉換為GPSMessage 對象 ,而不是引用或指針,那么最好的解決方案是使用轉換構造函數:

class GPSMessage : public ThreadedMessage
{
public:
    ...
    explicit GPSMessage(const ThreadedMessage& tm)
        : GPSMessage(static_cast<const GPSMessage&>(tm))  // Invoke copy-constructor
    {}
    ...
};

使用copy-constructor很好,但是它要求tm參數確實GPSMessage對象的引用。 否則無效。


另一個解決方案是使類具有多態性 (通過將析構函數設為virtualdynamic_cast ),並使用dynamic_cast指向指針。 如果結果為空指針,則msg不是GPSMessage開頭。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

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