Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/cplusplus/150.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/3/templates/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
类来获取基的任何子类 我认为这是一个简单的问题,但是我的C++知识也是如此。_C++_Templates - Fatal编程技术网

类来获取基的任何子类 我认为这是一个简单的问题,但是我的C++知识也是如此。

类来获取基的任何子类 我认为这是一个简单的问题,但是我的C++知识也是如此。,c++,templates,C++,Templates,我有一个班叫学习者: template <class T> class Learner { T* _someRef; (...) } 模板 课堂学习者{ T*_someRef; (...) } 以及对象从中继承的基类 我的想法是让学习者接受任何子类基础的对象,例如Base1、Base2等。我可以用C++ 11的Type特性来断言这个类型。问题是,我需要为每个基本扩展提供模板专门化,例如: template Learner<T>::Learner(...) { //

我有一个班叫学习者:

template <class T>
class Learner {
 T* _someRef;
 (...)
}
模板
课堂学习者{
T*_someRef;
(...)
}
以及对象从中继承的基类

我的想法是让学习者接受任何子类基础的对象,例如Base1、Base2等。我可以用C++ 11的Type特性来断言这个类型。问题是,我需要为每个基本扩展提供模板专门化,例如:

template Learner<T>::Learner(...) { //implementation };
// However I am required to declare template-specifications for each Base
// derived type, else I'll get compiler errors. This seems useless as
// the generic-inplementation will still be called, but requires me to
// specify a declaration for each Base extension.What if I have n Base
// extensions, makes no sense to do this for 50 Base extensions.
template Learner<Base1>::Learner(...);
template Learner<Base2>::Learner(...);
模板学习者::学习者(…){//implementation};
//但是,我需要声明每个基地的模板规格
//派生类型,否则我将得到编译器错误。这似乎毫无用处
//泛型实现仍将被调用,但需要我
//为每个基扩展指定一个声明。如果我有n个基扩展呢
//扩展,对于50个基本扩展这样做没有意义。
模板学习者::学习者(…);
模板学习者::学习者(…);

这在一定程度上违背了我试图实现的目的,因为每个类的操作都是相同的,因为它们都实现了Base的虚拟函数。我怎样才能做到这一点?制作n模板规范似乎不正确。。。它适用于少量扩展,但如果难以处理,则适用于较大数量的扩展。

如果我理解您的问题,我认为您需要的是
static\u assert

template<typename T>
struct Foo {
   static_assert(is_base_of<Base, T>::value, "T must inherit from Base");
};
模板
结构Foo{
静态_断言(是_base_of::value,“T必须从base继承”);
};
对于C++11,您需要提供一条消息:

此外,如果需要,还可以使用type_traits进行编译时检查:

模板
课堂学习者
{
静态断言(std::is_base_v);
T*_someRef;
// ...
};

除了
静态断言(…)
为了帮助解决虚拟继承的问题,您可以在派生类中使用关键字
override
,如下所示:

class Base {
public:
    virtual doSomething() = 0; // purely virtual
};

class DerivedA : public Base {
public:
    virtual doSomething() override;
};

class DerivedB : public Base {
public:
    virtual doSomething() override;
};
这样有助于避免任何歧义

编辑

我添加此部分是为了看看它是否有助于OP:

template <class T>
class Learner {
    T* _someRef;

public:
    Learner() { _someRef = new T(); }

    ~Learner() {
        if ( _someRef != nullptr ) {
           delete _someRef;
           _someRef = nullptr;
        }
    }

    void caller() {
        _someRef->doSomething();
    }
};

class Base {
public:
    virtual void doSomething() = 0;
};

class D1 : public Base {
public:
    virtual void doSomething() override {
        std::cout << "D1's doSomething was called" << std::endl;
    }
};

class D2 : public Base {
public:
    virtual void doSomething() override {
        std::cout << "D2's doSomething was called" << std::endl;
    }
};

int main() {
    Learner<D1> ld1;
    Learner<D2> ld2;
    ld1.caller();
    ld2.caller();

    _getch();
    return 0;
}
如果我们尝试这样做:

{
    Learner<D3> ld3; // compiler error
    Learner<D3> ld3( 5 ); // compiler error
    Learner<D3> ld3( D3( 5 ) ); // compiler error
    D3 d3(5);
    Learnder<D3> ld3( d3 ); // compiler error
}
我希望这能帮助您理解使用类模板进行专门化和/或部分专门化的原因。对于默认的可构造完整类型,您不需要专门化,但是对于非默认类型,您可以从其他方面考虑,它们被视为不完整类型


根据您的代码库,您可能不必专门化每个子类。这完全取决于它们是如何构造的,以及它们是否是完整类型。

与您的问题无关,但我对混合运行时多态性工具(虚拟+继承)和静态多态性工具(模板)的想法有点困惑。也许你有正当的理由这么做@可悲的是,我不知道这两者之间的区别。最有可能的是,我只是在想,就像我说的,我的C++知识很稀少。每个派生类的虚拟方法都可以用覆盖来简单声明。问题是,《学习者声明》要求我为每个基类派生提供专门化声明。@Horus ah okay不确定,因为您显示的代码量很小。至于静态断言(…),这不是我的优势之一,至于部分专业化。。。首先,谢谢你的回复。然而,很可能是因为我没有正确地表达自己,这不是问题所在。请看我和方济各格勒在Op(我的)初始帖子上的评论。谢谢你的帮助。我的问题的答案可以在这里找到:
class D3 : public Base {
private:
    unsigned int _x;
public:
    explicit D3( unsigned int x ) : _x( x ) {}

    virtual void doSomething() override {
        std::cout << "D3's doSomething was called: constructed with " << _x << std::endl;
    }
};
{
    Learner<D3> ld3; // compiler error
    Learner<D3> ld3( 5 ); // compiler error
    Learner<D3> ld3( D3( 5 ) ); // compiler error
    D3 d3(5);
    Learnder<D3> ld3( d3 ); // compiler error
}
template<>
class Learner<D3> {
private:
    D3* _d3;
public:
    explicit Learner( unsigned int x ) {
        _d3 = new D3( x );
    }

    explicit Learner( D3 d3 ) {
        _d3 = new D3( d3 );
    }

    ~Learner() {
        if ( _d3 != nullptr ) {
            delete _d3;
            _d3 = nullptr;
        }
    }

    void caller() {
        _d3->doSomething();
    }
};
{    
Learner<D3> ld3a( 7 );
ld3a.caller();
D3 d3( 5 );
Learner<D3> ld3b( d3 );
ld3b.caller();
}