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