寻找c ++成员函数覆盖的解决方案(非虚拟)

时间:2011-07-22 01:52:05

标签: c++ inheritance override

我有两节课:

struct A {

    template <typename T>
    void print(T& t){ 
        // do sth specific for A
    }
};

struct B : A {

    template <typename T>
    void print(T& t){ 
        // do sth specific for B
    }
};

在这种情况下,由于没有虚拟模板,因此无法编译具有虚函数(A和B都继承自)的更一般的Base类。当我试图将所有A或B对象委托给同一个“界面”时,是否有人有想法解决这个问题?先感谢您。

此致 君

5 个答案:

答案 0 :(得分:3)

您可以考虑使用CRTP

template<typename Derived>
struct Base {
  template <typename T>
  void print(T& t){ 
    static_cast<Derived*>(this)->print(t);
  }
};

struct A : Base<A> {
// template print
};

struct B : Base<B> {
// template print
};

示例用法:

template<typename T, typename ARG>
void foo (Base<T>* p, ARG &a)
{
  p->print(a);
}

此方法将被称为

foo(pA, i); // pA is A*, i is int
foo(pB, d); // pB is B*, d is double

这是another demo code

答案 1 :(得分:2)

使用代理类获取B的方法

  class A {
    public:
        friend class CProxyB;
        virtual CProxyB* GetCProxyB() = 0;
    };

    class B;
    class CProxyB
    {
    public:
        CProxyB(B* b){mb = b;} 
        template <typename T>
        void printB(T& t)
        { 
            mb->print(t);
        }       

        B* mb;
    };

    class B:public A {
    public:
        virtual CProxyB* GetCProxyB(){return new CProxyB(this);};

        template <typename T>
        void print(T& t){ 
            printf("OK!!!!!\n");
        }
    };


    int _tmain(int argc, _TCHAR* argv[])
    {
        A* a = new B;

        CProxyB* pb = a->GetCProxyB();

        int t = 0;
        pb->printB(t);

        return 0;
    }

答案 2 :(得分:0)

两个选项:

选项一:虚拟化方法,如果用户没有提供实现,则使用Base类。

 
template <typename T>
struct A {
    virtual void print(T& t);
};

template <typename T>
void A::print(T& t) {
    // do sth specific for A
}

template <typename T>
struct B : A {
    virtual void print(T& t);
};

void B::print(T& t) {
    // do sth specific for B
}

 

选项二:抽象方法,如果用户不提供实现,代码将无法编译。

 
template <typename T>
struct A {
    virtual void print(T& t)=0;
};

template <typename T>
struct B : A {

    virtual void print(T& t){ 
        // do sth specific for B
    }
};
template <typename T>
void B::print(T& t){ 
    // do sth specific for B
}
 

除了上面提到的,如果你不使它们成为虚拟,Derived类将使用Shadow the Base类方法,这肯定不是你想要的。因此,不可能。

答案 3 :(得分:0)

  

我的问题是如何使用指向不同A或B对象的单个指针。

您可以在没有虚拟功能的情况下执行此操作。但你真正要做的就是编写一个V表和虚函数的实现。

如果我要手动实现虚函数,我会将它全部基于Boost.Variant对象。该变体将有效地保存每个类的成员数据。要调用函数,请使用变体访问者函子。每个“虚函数”都有自己的访问者函子,对于变体中的每个可能的类型都会有不同的operator()重载。

所以你可能有这个:

typedef boost::variant<StructA, StructB, StructC> VirtualClass;

您可以在变体中存储这些对象中的任何一个。您可以在对象上调用“虚函数”,如下所示:

VirtualClass someObject(StructA());
boost::apply_visitor(FunctorA(), someObject);

类FunctorA是您的虚函数实现。这是一个访客,定义如下:

class FunctorA : public boost::static_visitor<>
{
  void operator()(StructA &arg){
    //Do something for StructA
  }

  void operator()(StructB &arg){
    //Do something for StructB
  }

  void operator()(StructC &arg){
    //Do something for StructC
  }
}

访问者可以拥有由apply_visitor返回的返回值。他们可以通过将参数存储为访问者类的成员来获取参数。等等。

最重要的是,如果您更改了变体类型,要添加新的“派生类”,您将会遇到任何没有新类型重载的仿函数的编译器错误。

但说实话,你应该只使用虚拟功能。

答案 4 :(得分:0)

通过使用CRTP(Curiously recurring template pattern),您可以在没有虚拟的情况下实现静态polymorphsim。

#include <iostream>
using namespace std;
#define MSG(msg) cout << msg << endl;

template<class Derived>
class Base{
public:
    void print()
    {
        static_cast<Derived*>(this)->print();
    }
};

class Derived1 : public Base<Derived1>
{
public:
    void print()
    {
        MSG("Derived 1::print");
    }


};

class Derived2 : public Base<Derived2>
{
public:
    void print()
    {
        MSG("Derived 2::print");
    }
};

template<class T>
void callme(Base<T>& p)
{
     p.print();
}

int main() 
{
    Base<Derived1> p1;
    Base<Derived2> p2;
    callme(p1);
    callme(p2);
    system("pause");
    return 0;
}

//Result :
//Derived 1::print
//Derived 2::print