C++模版類如何動態獲取類型?
我用C++寫一個小工具的時候發現不知道如何處理模版類型。B類和C類都繼承於A類,D類是一個封裝了類成員函數指針功能的模板類。
在A類中有一個C類的對象,但是這個模板對象C所需要的類型如何動態獲得?我主要是想在A類中調用B類和C類傳入的類成員函數。
因為B類和C類中各有一個不是從A類繼承得來的函數,如果直接把類型寫A的話就不能通過C類的類成員函數指針調用B類或C類的那個獨立的函數了,模板類型該如何動態獲取?或者還有什麼更好的設計方式?
代碼:
class A{
private:
D&<這裡怎麼寫&> d;public:
A(){
}
void setD(D d){
this-&>d = d;
}void run(){
this-&>d.go();
}};
class B : A{
public:
B(A* a){
a-&>setD(D&(this, B::bbb));
}void bbb(){
}
};
class C : A{
public:
C(A* a){
a-&>setD(D&(this, C::ccc));
}void ccc(){
}
};
template&
class D{
private:
T* object;
typedef void (T::*Function)(void);
Function function;public:
D(T* object, Function function) : object(object), function(function){
}
void go(){
(this-&>object-&>*(function))();
}
};int main(){
A* a = new A();B* b = new B(a);
a-&>run();C* c = new C(a);
a-&>run();return 0;
}
題主更新問題了,答案也是一個簡單的技巧。說來搞這麼複雜幹什麼呢,用lambda表達式然後轉成function&
class Fuck
{
public:
virtual ~Fuck() = default;
virtual void go();
};
class A
{
private:
shared_ptr&
...
};
...
template&
class D : public Fuck
{
private:
T* object;
typedef void (T::*Function)(void);
Function function;
public:
D(T* object, Function function) : object(object), function(function){
}
void go() override{
(this-&>object-&>*(function))();
}
};
==================================
不知道題主想問什麼,但是我猜多半可能是WTL的那種技巧:論如何不用虛表模擬虛函數
過度優化前:
class Bitch
{
public:
virtual void Eat(Shit shit) = 0;
void EatTwice(Shit shit)
{
Eat(shit);
Eat(shit);
}
};
class TrueBitch : public Bitch ...;
class FalseBitch : public Bitch ...;
過度優化後:
template&
class Bitch
{
public:
TBitch* TheRealMe()
{
return static_cast&
}
void EatTwice(Shit shit)
{
TheRealMe()-&>Eat(shit);
TheRealMe()-&>Eat(shit);
}
};
class TrueBitch : public Bitch&
{
public:
void Eat(Shit shit) { ... }
};
class FalseBitch : public Bitch&
{
public:
void Eat(Shit shit) { ... }
};
如果你只是想實現針對BC,同一個函數能有不同的執行,那虛函數不就是為此而生的嘛,都用C++了何苦折騰函數指針。
如果兩個函數參數有不同,拿現成的function、lambda包一下不就好了,你的D類不就是為了實現這種功能嗎?(而function實質是構建了一個匿名類並重載(),而不是用模版類)
而如果你要通過A去調用只有C里有的方法呢?這就在設計說不通了啊。
就像人和貓都繼承於動物,你卻想讓一個動物去「膜」,很明顯貓是做不到的啊。
如果你就是想要效率,或者就是要自己操作函數指針,那麼就不要想著「動態獲取類的信息」或者「保存類的信息」了,直接擦去類型信息,通通強制轉換成類似A::func的指針好了,反正是建立在thiscall的基礎上,函數返回值/參數也相同。
大家都貼代碼,那我也貼一段吧
class A;
typedef void (A::*func)();
class A
{
protected:
func theFunc;
A *obj;
A(func f, A *obj_) : theFunc(f), obj(obj_) {}
public:
void go()
{
(obj-&>*theFunc)();
}
};
class B : public A
{
private:
void bbb() { printf("bbb
"); }
public:
B() : A((func)B::bbb, (A*)this) { }
};
class C : public A
{
private:
void ccc() { printf("ccc
"); }
public:
C() : A((func)C::ccc, (A*)this) { }
};
int main()
{
A *b = new B();
A *c = new C();
b-&>go();
c-&>go();
getchar();
}
另外誰能告訴我為什麼輪子哥的縮進是4格,我的卻成了8格?我本地也是4空格的tab啊。
在 @XZiar 的回答的幫助下,參考了代碼解決了這個問題。
此題無需使用模板,先睡覺,佔個坑,以後有空再答
想要的是c++的委託方式吧
class A {
std::function&
public:
void set(std::function&
void run(){ if (_x) _x(); }
};
class B {
void Do(){
//do some thing;
printf("do B job.
");
}
public:
B(A a){ a.set([this](){this-&>Do();});}
};
class C {
void Do(){
//do some thing;
printf("do C job.
");
}
public:
C(A a){ a.set([this](){this-&>Do();});}
};
int main(){
A a;
B b(a);
a.run();
C c(a);
c.run();
return 0;
}
我覺得題主你對模版理解有些偏差,在運行時,A中的d應當是類型確定的。
感覺你想做的應當是在運行時,由B類型的對象通知A的對象:「把我的方法綁到你身上吧,你需要使用我的方法來run()」, 所以我覺得使用綁定更合適:
#include &
#include &
#include &
class TestClass // 這就是你的B類型
{
private:
int x = 100;
public:
void print()
{
std::cout &<&< x &<&< std::endl;
}
};
class Accepter // 這就是你的A類型
{
public:
void set_func(TestClass a)
{
this-&>_func = std::bind(TestClass::print, a);
}
void run()
{
this-&>_func();
}
private:
std::function&
};
int main()
{
Accepter accepter;
TestClass testClass;
accepter.set_func(testClass);
accepter.run();
system("pause");
return 0;
}
使用C++ 11的std::bind和std::function來實現。
類D不需要是模板:
class A;
class D{
private:
A* object_;
typedef void (A::*Function)(void);
Function function_;
public:
D() : object_(NULL), function_(NULL) { }
template&
D(A* object, void (T::*function)()) : object_(object), function_((Function)function){
}
void go(){
(object_-&>*function_)();
}
};
class A{
private:
D d_;
public:
A(){ }
void setD(const D d){
d_ = d;
}
void run(){
d_.go();
}
};
class B : public A {
public:
B(A* a){
a-&>setD(D(this, B::bbb));
}
void bbb(){
}
};
class C : public A {
public:
C(A* a){
a-&>setD(D(this, C::ccc));
}
void ccc(){
}
};
int main(){
A* a = new A();
B* b = new B(a);
a-&>run();
C* c = new C(a);
a-&>run();
return 0;
}
推薦閱讀:
※c++中如何正確實現克隆(原型)模式?
※實現同一介面的不同類使用組合實現了多態,但是這破壞了DRY嗎?
※設計模式在實際開發中用的多嗎?
※設計模式之組合模式
※設計模式之工廠模式