簡體   English   中英

為什么從 base 到派生的 static_cast 轉換在 base 內部而不在外部有效

[英]Why static_cast conversion from base to derived works inside base but not outside

為什么從基類到派生的 static_case 轉換在基類內部有效,但在基類之外不起作用

#include <iostream>
using std::cout;

class Base
{
public:
    template <typename T>
    int getValue() const { return static_cast<const T&>(*this).getValue(); }
};

class Derived: public Base
{
public:
    Derived(int v): value(v) { }
    int getValue() const { return value; }
    int value;
};

class Another
{
    int getValue() const { return 5; }
};

template <typename T>
void out(const Base & base) {
    cout << base.getValue<T>() << '\n';
}

int main() {
    Derived d(5);
    Base b;
    out<Derived>(d);    //understandable, d has derived part.
    out<Derived>(b);   //don't understand, b is only base.
    out<Another>(b);    //compile time error   
    //static_cast<Derived>(b);   //compile time error
}

我閱讀這篇關於 CRTP 的文章並偶然發現了這段代碼:

template <typename T>
class Base
{
public:
    void doSomething()
    {
        T& derived = static_cast<T&>(*this);
        use derived...
    }
};

class Derived : public Base<Derived>
{
    ...
};

而且我也不清楚轉換在這里是如何工作的。

main() 中的最后一次轉換在語法上是不正確的,並且不等同於模板中的代碼,您不能將對象向上轉換為對象(您可以向下轉換,導致類型收縮)。 在上面的模板中,您可以轉換引用。

Derived&可以綁定到Base&static_cast沒有辦法檢查它。 CRTP 確保了this一點,因為在 Derived 類型的存儲點上, *this導致引用可以安全地轉換為Derived&引用對象。

參照Another不能被結合到參照Base ,當Base不是基類的Another 在這種情況下,使用static_cast轉換指針或引用是非法的。

模板代碼是合法的,在 CRTP 工作的情況下,因為模板代碼在 Derived 是完整的類型的地方被設置,即在使用模板的地方。 模板本身不生成任何東西,也不編譯,只檢查正確性。

盡管如此,在 CRTP 中有些事情是不可能的,例如在基類內部使用派生類中的嵌套類型聲明作為完整類型,原因很簡單:它們不完整並且不受前向查找的影響,不像成員變量和職能。 如果需要這樣的使用,則必須在 Base 之前定義第三種類型,包含必需的聲明。

僅當此轉換合法時才應使用static_cast轉換。 在您的代碼中,您正在創建Base類的對象,並嘗試將其轉換為Derived類。 幸運的是, Derived::getValue()實現不使用任何數據成員,並從文字返回一個值。 無論如何,這是未定義的行為。

在 CRTP 的情況下,不會創建Base類的實例:僅使用Derived實例。

更新。 嘗試這個:

//static_cast<Derived>(b);   doesn't compile
static_cast<Derived&>(b);   shall compile

更新 2。因為Derived::getValue()使用數據成員(在您的代碼的初始版本中未使用數據成員Derived::getValue()所以您會得到垃圾。

這是 C++ 規則的一部分。 static_cast可用於將基類表達式轉換為派生類。 如果在運行時,該對象實際上不是派生類對象的基類子對象,則它是未定義的行為,無需診斷。

你的問題的第一句話是不正確的,這個演員可以寫在代碼的任何一點。

out<Another>()無法編譯,因為AnotherBase沒有繼承關系。

暫無
暫無

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

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