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& d;
...
};

...

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&(this);
}

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& _x;
public:
void set(std::function& x) { _x = x; }
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& _func;
};

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嗎?
設計模式在實際開發中用的多嗎?
設計模式之組合模式
設計模式之工廠模式

TAG:軟體工程 | 設計模式 | CC | 泛型Generic | 模板C |