簡體   English   中英

有沒有辦法在超類構造函數中知道調用對象的子類? C++

[英]Is there a way to know in the superclass constructor the subclass of the calling object? C++

假設我有類似的東西:

class A 
{
  public:
     A(A* owner)
     {
        m_owner=owner;
        if (dynamic_cast<B*>(this))
        {
          m_id=sm_bid; 
          sm_bid++;
        }
        else
        {
          m_id=sm_aid;
          sm_aid++;
        }
     }
  private:
    int m_id;
    A*  m_owner;
    static int sm_aid;
    static int sm_bid;
};

A::sm_aid=0;
A::sm_bid=0;

class B: public A
{
    B(A* owner) : A(owner) {}
};

不幸的是,dynamic_cast 無法捕捉到它是一個 B 對象(實例化時)。 這聽起來合乎邏輯(因為之前調用了超類中的構造函數來調用子類中的構造函數。有沒有辦法實現這樣的功能?

您的設計看起來很復雜,幾乎可以肯定可以在不需要知道它是派生的情況下實現。

但是,用 C++ 打自己的腳是神聖的權利 :) 因此,您可以嘗試使用Curiously Recurring Template Pattern (CRTP)來實現您的目標(通過靜態多態在構造函數中實現多態行為)。

這是快速而骯臟的草圖

#include <iostream>
#include <type_traits>

struct Owner
{};

struct B;

template <class Derived>
struct A : public Owner
{
    A(Owner*)
    {
        if (std::is_same<Derived, B>::value)
            std::cout << "called from derived B" << std::endl;
        else
            std::cout << "not called from derived B\n" << std::endl;
    }
};

struct B : public A<B>
{
    B(Owner* owner) : A<B>(owner) {}
};

int main()
{
    A<void> a(nullptr);
    B b(&a);
}

輸出:

not called from derived B
called from derived B

注意:我注意到您正在使用靜態變量進行計數。 請注意,每個模板實例化都有自己的靜態變量!

首先, dynamic_cast工作,您需要在基類中至少有一個虛擬方法(通常析構函數是虛擬的,因為您經常出於其他原因需要它)。

其次,在構造A子對象時,在A的構造函數中,所有虛函數都將引用A的類定義(即使您實際上A構造為B的子對象),並且dynamic_cast會說this不是類型B

這是因為在B構造函數完成之前,該對象不是類型B的對象,因此任何和所有嘗試確定它是否是類型B都會說這不是因為該對象實際上不是類型B (然而)。

我希望這可以為您解決一些困惑。

編輯:
我剛剛注意到你問題下的最后一段,你在那里尋求解決方案。

如果不了解有關問題的更多信息,將很難真正幫助您實現此功能。 我的建議是不要這樣做,也許完全使用另一個類來為您的對象分配 id,而不是嘗試讓A這樣做。

如果它真的必須在A那么這可能會有所幫助:

struct A
{
  template <class FinalType>
  A(A* owner, FinalType *){...}//use std::is_same to check if `B` or not
};

struct B : A
{
  B(A * owner):A(owner, this){}
};

如果A是抽象類型,則可以使用基於標簽的重載技術。

class B;
class C;

class A
{
public:
    template<class Derived>
    struct my_derived
    {
        using type = Derived;
    };

protected:
    explicit A(my_derived<B>)
    {
        // Do whatever you want when derived is B
    }

    explicit A(my_derived<C>)
    {
        // Do whatever you want when derived is C
    }

private:

};

class B : A
{
public:
    B() : A(A::my_derived<B>())
    {
    }
};

class C : A
{
public:
    C() : A(A::my_derived<C>())
    {
    }
};

另一種方法是 AMA 建議的基於模板的編程。 但是盡管模板是 C++ 中的強大功能,但它們也有自己的問題。 它們不能在 cpp 文件中實現。 它們會導致代碼膨脹,從而影響性能,因為更大的代碼大小會導致更高的指令緩存未命中率。

所以我認為這種方法比RTTI更好, RTTI會影響運行時性能,並且您必須在基類中聲明一個虛擬函數,以及基於模板的方法。

看起來這很好用:

#include <iostream>
#include <type_traits>

class Owner
{};

class B;

template <class Derived>
class A : public Owner
{
    public:
    A(Owner* owner)
    {
        m_owner=owner;
        if (std::is_same<Derived, B>::value)
            std::cout << "called from derived B" << std::endl;
        else
            std::cout << "not called from derived B\n" << std::endl;
    }
    private:
    Owner* m_owner;
};

class B : public A<B>
{
    public:
    B(Owner* owner) : A<B>(owner)
    {}
};

int main()
{
    A<void> a(nullptr);
    B b(&a);
}

向 AMA 致敬。 任何事情都可以在 C++ 中完成

暫無
暫無

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

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