2016-07-13 28 views
0

我知道这看起来很复杂,但我希望有人可能在这里指出我的错误。我相信这个设计会在你的嘴里留下不好的味道,我很高兴听到设计方案。但形式来自问题领域的建模。由于无法解析模板参数而导致多态性失败?

我敢肯定,我很愚蠢,但有一些关于模板与继承的方式相混淆,这让我感到困惑。下面是说明一些相比下来代码如下:

// main.cpp 

#include <cstdio> 

template <typename POD> 
class A { 
public: 
    POD data; 
    POD get_a() { return data; } 
}; 

template <typename T> 
class B { 
public: 
    virtual void do_something_with_an_A_child(const T&) = 0; 
}; 

class ADerived : public A<float> { 
public: 
    ADerived(float a) { data = a; } 
}; 

class BDerived : public B<ADerived> { 
public: 
    virtual void do_something_with_an_A_child(const ADerived& someA) { 
    printf("A bit of A-type's data: %f\n", someA.data); 
    } 
}; 

template <typename POD> 
class Aggregator { 
public: 
    A<POD>* instanceOfA; 
    B<A<POD>>* instanceOfB; 
    Aggregator(A<POD>* anA, B<A<POD>>* aB) : instanceOfA(anA), instanceOfB(aB) {} 
}; 

int main() { 
    ADerived myADerived(3.14159f); 
    BDerived myBDerived; 

    Aggregator<float> myAggregator(&myADerived, &myBDerived); 

    return 1; 
} 

所以A是一个类模板的签名只是一些内置的类型。 (在我的具体情况中,A具有对其内部数据进行操作的方法。)类B旨在承诺为某个特定实例A<.>指定的某些操作的接口。因此,在上面的代码中,您看到我将AB定义为模板类,然后创建从这些模板类继承的类,给出ADerivedBDerived

(在现实情况下,A代表的数学模型和一些数据,并B是对模型进行数学优化的界面。)

现在,它应该有联系的情况下,一类ADerivdedBDerived(为了创建基于它们接口的通用算法)我调用Aggregator,它只是在构造函数中使用一些指针。我只希望Aggregator需要知道POD类型,因为它仅用于操纵接口,而不用担心对象包含的内容太多。

我从clang++以下编译器错误与-std=c++14

main.cpp:42:21: error: no matching constructor for initialization of 'Aggregator<float>' 
    Aggregator<float> myAggregator(&myADerived, &myBDerived); 
        ^   ~~~~~~~~~~~~~~~~~~~~~~~~ 
main.cpp:35:3: note: candidate constructor not viable: no known conversion from 'BDerived *' to 'B<A<float> > *' for 2nd argument 
    Aggregator(A<POD>* anA, B<A<POD>>* aB) : instanceOfA(anA), instanceOfB(aB) {} 
^

的意思很清楚,但我不知道为什么它不能看到一个BDerivedB<A<float>>。我的意思是,它具体是B<ADerived>,但ADerivedA<float>,因此BDerived应被视为B<A<float>>。这显然不是这种情况,所以无论我做些什么愚蠢的事情,希望有人指出它,或者这在C++中是不可能的,我需要一些替代设计建议。

+1

'乙'和'乙>'是完全不同的类型,如果'ADerived'从'甲'或不继承不要紧。您的设计看起来不正确,但很难提出任何建议,没有足够的信息 – Slava

+1

建议,通常更容易实现您需要的特定类型而无需模板,然后对其进行概括。 – Slava

+0

谢谢@Slava。相信与否,这是从我已经为特定类型编码的算法中提取出来的尝试。我试图将我的API概括为一个库/框架。很难得到正确的结果,我很确定我没有。但我想我们都以某种方式学习。 – Timtro

回答

2

模板参数是静态解析的,并且是确切类型。因此即使ADerivedA<POD>的后代,B<ADerived>也不会衰减到B<A<POD>>。你可能工作这个由各地:

  • 以多一个模板参数,T,在Aggregator和可选确保(使用std::enable_if<>std::is_base<>),其A<POD>T一个基站,或
  • 暴露TB使用typedef,然后在Aggregator中取T并在Aggregator中存储TA<B::T>
+1

谢谢。你激励我找到我需要的答案。我将采用派生类的类型作为模板参数,并使用'auto'和'decltype(。)'获取有关返回类型的信息,因为我需要它。这样,只有原始的'A'需要知道POD类型。 – Timtro

相关问题