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

looking for solution of c++ member function override (non virtual)

本文关键字:虚拟 解决方案 c++ 成员 函数 覆盖 寻找      更新时间:2023-10-16

我有两个类:

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都继承了虚函数),因为没有虚的for模板。由于我试图将所有A或B对象委托给同一个"接口",有人有办法解决这个问题吗?提前谢谢你。

真诚,小君

您可以考虑使用使用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

使用代理类获取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;
    }

两个选项:

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


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
}
 

除了上面提到的,如果您不使它们成为虚的,派生类将会遮蔽基类方法,这肯定不是您想要的。因此,不可能的。

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

您可以在没有虚函数本身的情况下做到这一点。但是你真正要做的是编写一个v表和虚函数的实现。

如果我要手动实现虚函数,我会将其全部基于Boost。变体对象。该变体将有效地保存每个类的成员数据。要调用函数,可以使用一个变体访问函子。每个"虚函数"都有自己的访问函子,对于变体中每种可能的类型,该访问函子都有不同的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返回。它们可以接受实参,方法是将实参存储为visitor类的成员。等等

最好的是,如果你曾经改变你的变体类型,添加新的"派生类",你将得到编译器错误的任何函数没有重载的新类型。

但说实话,你应该只使用虚函数

通过使用CRTP(奇怪的重复模板模式),您可以实现静态多态,而不需要虚拟。

#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