簡體   English   中英

具有奇怪的重復模板模式的派生類中的損壞的成員變量

[英]Corrupt member variable in derived class with Curiously Recurring Templating Pattern

我目前正在使用CRTP,遇到的問題是派生類中的成員變量被損壞,也就是具有垃圾值(當前有4種多態性,其中最基本的基類為“ A”,最底層的派生類稱為“ D”)。

這是一些顯示此問題示例的代碼:

//A.hpp
template <class TB>
class A {
public:
    A();
    void CRTP_func();
};

template <class TB>
A<TB>::A() {
    std::cout << "A constructor called!" << std::endl;
}

template<class TB>
void A<TB>::CRTP_func() {
    std::cout << "CRTP_index called in A" << std::endl;
    static_cast<TB*>(this)->CRTP_func2();
}

//B.hpp
#include "A.hpp"
#include <vector>

template<class TC>
class B : public A<B<TC>>
{
public:
    B();
    void CRTP_func2();
};

template<class TC>
B<TC>::B() {
    std::cout << "B constructor called!" << std::endl;
}

template<class TC>
void B<TC>::CRTP_func2() {
    std::cout << "CRTP_func called in B" << std::endl;
    static_cast<TC*>(this)->CRTP_func3();
}

//C.hpp
#include "B.hpp"

template<class TD>
class C : B<C<TD>> {
public:
    C();
    void CRTP_func3();
    int x;
};

template<class TD>
C<TD>::C() {
    std::cout << "C constructor called" << std::endl;
}

template<class TD>
void C<TD>::CRTP_func3() {
    std::cout << "CRTP_index3 called in C" << std::endl;
    static_cast<TD*>(this)->CRTP_func4();
}


//D.hpp
#include "C.hpp"

    class D : C<D> {
    public:
        D();
        bool onInit();
        void CRTP_func4();
        C<D> top;
        int y = 0;

    };

D::D() {
    std::cout << "D constructor called!" << std::endl;
}

bool D::onInit() {
    std::cout << "D onInit called!" << std::endl;
    y = 5;
    return true;
}

void D::CRTP_func4() {
    std::cout << y << std::endl;
    std::cout << "CRTP_index4 called in D! " << std::endl;
}

//main.hpp
int main {
D * D_ptr = new D();
    D_ptr->onInit();
    D_ptr->top.CRTP_func3();
    return 0;
}

如您所見,A是基類,而D是派生類,如下所示:

A<B<C<D>>>

該程序的輸出如下:

A constructor called!
B constructor called!
C constructor called
A constructor called!
B constructor called!
C constructor called
D constructor called!
D onInit called!
CRTP_index3 called in C
-33686019
CRTP_index4 called in D!

值-33686019在D.hpp中打印出來,在其中打印值y,並在初始化時將其設置為5。 經過一番挖掘后,我檢查了main.cpp中的值,即使在進行了這些CRTP調用后也將其設置為5,但仍會打印出垃圾值。

經過更多調試后,我意識到刪除該行

int x;

B.hpp中的問題解決了這個問題,所以我認為這個問題與不對中有關,但是我不確定為什么會這樣。 有誰知道為什么會發生或如何解決?

對冗長的帖子和含糊不清的代碼很抱歉,我試圖消除大多數復雜性,並為帖子着想盡可能簡化代碼。

更新:

感謝下面的評論,我找到了解決問題的方法。 代替使用D::top ,更好的方法是在主文件中這樣創建一個指針:

C<D> * C_ptr = static_cast<C<D>*>(D_ptr);

然后像這樣從那里調用CRTP_func3()

C_ptr->CRTP_func3();

這按預期工作。

您對靜態類型為C<D>D::top )的對象調用函數CRTP_func3() )。 函數C<D>::CRTP_func3()執行static_cast<D*>(this)但是對象沒有預期的類型。 因此,行為是不確定的。

從邏輯上講,您遇到的最基本問題是,您期望D_PtrD_Ptr->topy值相同(您說的是5)。 D_Ptr->top是一個完全不同的實例,即使它最終從D派生,也將具有自己的y副本。

然后, DC派生的,因此,無論模板有多瘋狂, C基本上都不可能從D派生。 這是您通過在C的this指針上調用CRTP_func4做出的假設。

此外,該函數調用假定模板類型TDD的實例。 該函數調用存在於C內,這是C做出的瘋狂假設-盡管我認為在這種情況下它恰好是正確的。 (如果不是則編譯器會捕獲該代碼)

最后關於crtp的問題:考慮拒絕撒但及其一切方式。

但是,嚴重的是,顯然沒有完整的替代方法,但是我想您會發現,如果您充分考慮了接口(或C ++中的pure abstract classes )的強大功能, 也許可以找到一種使用它的方法。 並且具有(幾乎)相同的性能...當然,我不知道您的特定問題,但是我強烈建議您對本文進行長時間仔細的研究https://en.wikipedia.org/wiki/ Composition_over_inheritance

特別要看第二個示例代碼塊,它是用C#編寫的(其中interface將是C ++中的pure abstract class )。 請考慮一下這種模式是否可以幫助您。

暫無
暫無

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

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