调用派生类的模板函数 我在C++中遇到一个问题,它在派生一个派生类的函数时有一个指向基类的指针。

调用派生类的模板函数 我在C++中遇到一个问题,它在派生一个派生类的函数时有一个指向基类的指针。,c++,templates,derived,boost-serialization,C++,Templates,Derived,Boost Serialization,编辑: 有些答案提到了我 但我的观点是,我需要一个指向“Base*”类而不是“Base*”类的指针,因为我不知道当前正在处理的类型(当前实例是从某种工厂创建的) 课程: 类基 { .. 模板 func(T arg){…}; }; 类Derived1:公共基 { ... 模板 func(T arg){…}; }; 类Derived1:公共基 { ... 模板 func(T arg){…}; }; 用法: intmain() { Base*BasePtr=new-Derived1(); //预期要

编辑: 有些答案提到了我

但我的观点是,我需要一个指向“Base*”类而不是“Base*”类的指针,因为我不知道当前正在处理的类型(当前实例是从某种工厂创建的)

课程:
类基
{
..
模板
func(T arg){…};
};
类Derived1:公共基
{
...
模板
func(T arg){…};
};
类Derived1:公共基
{
...
模板
func(T arg){…};
};
用法:
intmain()
{
Base*BasePtr=new-Derived1();
//预期要调用的函数是Derived1::func()
BasePtr->func();
返回0;/:)
}
我无法将func设置为虚拟,因为该语言不支持虚拟模板函数

仅当类具有模板参数时才允许,但如果其中的函数具有模板参数时则不允许

我看到Boost.Serialization中解决了类似的问题,但无法理解解决方案

谢谢

Koby Meir执行

说明:

template<typename D>
class Base 
{
public:
    template<typename T>
    void func (T arg) 
    {
         static_cast<D*>(this)->func(arg);
    }
};

class Derived1 : public Base<Derived1>
{
public:
    template<typename T>
    void func (T arg) { /*...*/ }
};


Base<Derived1> *basePtr = new Base<Derived1>();
basePtr->func(100);
模板
阶级基础
{
公众:
模板
无效函数(T参数)
{
静态_cast(this)->func(arg);
}
};
类Derived1:公共基
{
公众:
模板
void func(T arg){/*…*/}
};
Base*basePtr=新的Base();
basePtr->func(100);

请检查,它将帮助您实现CRTP。

现有的两种解决方案将动态多态性与静态多态性进行权衡。如果没有关于当前问题的更多细节,就不可能知道这是否是一种有效的方法,因为它基本上打破了多态层次结构:对于CRTP,没有单一的基类,而是一个基类家族。不能将
Derived1
Derived2
的对象保存在同一容器中,因为它们是不相关的。。。如果您只需要共享代码,而不需要动态多态性,那么这是一个很好的解决方案。看看访客模式和双重分派的类似问题

如果需要动态多态性,可以尝试实现双重分派(这是一种痛苦,但如果层次结构足够小,则是可行的。基本上创建两个不同的层次结构,一个位于
Base
,另一个作为手动调度程序的一部分。位于
Base
的层次结构将有一个虚拟方法
apply
,第二个层次结构将为每个层次结构提供虚拟功能。)第一层次结构中的一种类型:

class Base;
class Derived1;  // inherits from Base, implements Visitor
class Derived2;  // inherits from either Base or Derived2
struct Visitor {
   virtual void visit( Base& ) = 0;     // manually unrolled for all types
   virtual void visit( Derived1& ) = 0;
   virtual void visit( Derived2& ) = 0;
};
struct Base {
   virtual void apply( Visitor& v ) {   // manually replicate this in Derived1, 2
      v.visit( *this );
   }
   template <typename T> void foo(T);   // implement 
};

template <typename T>
struct FooCaller : Visitor {
    T& ref_value;
    FooCaller( T& v ) : ref_value(v) {}
    template <typename U> void call_foo( U& o ) {
       o.foo(ref_value);
    }
    virtual void visit( Base & b )      { call_foo(b); }
    virtual void visit( Derived1 & d1 ) { call_foo(d1); }
    virtual void visit( Derived2 & d2 ) { call_foo(d2); } 
};
类基;
类Derived1;//从基继承,实现Visitor
类Derived2;//从基或Derived2继承
结构访问者{
虚拟void访问(Base&)=0;//手动展开所有类型
虚拟无效访问(Derived1&)=0;
虚拟无效访问(Derived2&)=0;
};
结构基{
虚拟void apply(Visitor&v){//在Derived1、2中手动复制此项
v、 访问(*本);
}
模板void foo(T);//实现
};
模板
结构FooCaller:访问者{
T&ref_值;
FooCaller(T&v):参考值(v){}
模板无效调用_foo(U&o){
o、 foo(参考值);
}
虚拟无效访问(基本和b){call_foo(b);}
虚拟无效访问(Derived1和d1){call_foo(d1);}
虚拟无效访问(Derived2和d2){call_foo(d2);}
};
我使用的名称在Visitor模式中很常见,这种方法与该模式非常相似(我不敢称之为Visitor模式,但这种方法很相似,所以我只是借用了命名约定)

用户代码类似于:

int main()                     // main returns int, not void!!!
{
   Base* BasePtr = new Derived1();
   int i = 5;
   FooCaller<int> c(i)
   BasePtr->apply(c);          // [1] magic happens here
}
int main()//main返回int,而不是void!!!
{
Base*BasePtr=new-Derived1();
int i=5;
财务委员会(一)
BasePtr->apply(c);//[1]这里发生了魔法
}
事先声明
i
c
的要求可以通过将函数的参数从引用更改为常量引用(如果可能)来释放。实际的魔力在于[1]C++单调度机制SHIL将调用调度到<代码>派生:1:应用< /COD>,因为这是由代码> BasePTR < /C>所指向的对象的动态类型。在这一点上,它将调用<代码>访问者:访问(派生1:)。将自身作为参数。这将再次通过单一分派机制分派到
FooCaller::visit(Derived1&)
,此时两个对象都已解析为其静态类型。当
FooCaller::visit
调用
call\U foo
时,参数
U
被推断为
Derived1
,当它调用
Derived1::foo
时,参数被推断为
int
,并最终调用
Derived1::foo
>…虽然有几个循环和间接

根据您的特定用例,这可能太复杂(如果像CRTP这样的静态多态性可以工作)或太难维护(如果层次结构很大:对于
基本层次结构中的每个新元素,您必须更新
访问者的层次结构中的所有类型),所以如果你能避免这种复杂性,那就完美了。不过,在某些情况下,你需要这样做

还要注意的是,这是最复杂的全动态解决方案,根据运行时多态性的不同,在这两者之间还有其他选项……可能是这样的情况,您的层次结构为短裤访问者建模,并且您只需要手动展开将分派到模板的不同虚拟函数在内部,在这种情况下,上述复杂性的一半将消失

还注意到C++中的这一点非常不寻常,如果你解释实际问题,可能会有更好的简单解决方案,你所说的是对原始问题的解决方案的需求:动态地分配给模板。

class Base;
class Derived1;  // inherits from Base, implements Visitor
class Derived2;  // inherits from either Base or Derived2
struct Visitor {
   virtual void visit( Base& ) = 0;     // manually unrolled for all types
   virtual void visit( Derived1& ) = 0;
   virtual void visit( Derived2& ) = 0;
};
struct Base {
   virtual void apply( Visitor& v ) {   // manually replicate this in Derived1, 2
      v.visit( *this );
   }
   template <typename T> void foo(T);   // implement 
};

template <typename T>
struct FooCaller : Visitor {
    T& ref_value;
    FooCaller( T& v ) : ref_value(v) {}
    template <typename U> void call_foo( U& o ) {
       o.foo(ref_value);
    }
    virtual void visit( Base & b )      { call_foo(b); }
    virtual void visit( Derived1 & d1 ) { call_foo(d1); }
    virtual void visit( Derived2 & d2 ) { call_foo(d2); } 
};
int main()                     // main returns int, not void!!!
{
   Base* BasePtr = new Derived1();
   int i = 5;
   FooCaller<int> c(i)
   BasePtr->apply(c);          // [1] magic happens here
}