2015-08-26 32 views
1

我有一个模板类Specie< T>派生自基类Animal。我创建了一个指向Animal的指针矢量,以便将不同类型的对象Specie<T>存储在同一个矢量中。 T可以是狗,猫等......C++多态克隆模板类。不能使用克隆的对象作为参数在功能

现在我想在模板函数中使用vector的某些元素作为参数。我为不同的模板参数T编写了函数的不同特化,因此每个Specie<T>的行为都不相同。为了从矢量中获得正确类型的每个对象,我使用了多态克隆。它运作良好,我得到正确类型的对象Specie<T>(请参阅下面的非常简短的测试)。但是,当我想使用矢量的元素作为模板函数的参数时,它不起作用。

// Base class 
class Animal{ 

public: 
    virtual ~Animal() {} 

    virtual Animal *clone() = 0; 
    virtual void action() = 0; 

}; 


// Specific types of animals. Forward declaration 
class Dog; 
class Cat; 



// Templated derived class Specie 
template <class T> 
class Specie : public Animal{ 

public: 
    Specie<T> *clone(); 

    void action(); 

}; 





template <class T> 
Specie<T> * Specie<T>::clone() { 

    std::cout << "Cloning a Specie<T>" << std::endl; 
    return new Specie<T>(*this); 

} 



// Specialization of templated function action() for Dog 
template <> 
void Specie<Dog>::action(){ 

    std::cout << "Wouaf !" << std::endl; 

} 


// Specialization of templated function action() for Cat 
template <> 
void Specie<Cat>::action(){ 

    std::cout << "Miaouuu !" << std::endl; 

} 




class Interaction{ 

public: 

    template <class T1> 
    static void DoSomething(Specie<T1>); 

}; 



// Specialization of templated function DoSomething() for Dog 
template <> 
void Interaction::DoSomething(Specie<Dog> obj){ 

std::cout << "Interact with Dog !" << std::endl; 

} 


// Specialization of templated function DoSomething() for Cat 
template <> 
void Interaction::DoSomething(Specie<Cat> obj){ 

std::cout << "Interact with Cat !" << std::endl; 

} 




int main(){ 


Specie<Cat> HelloKitty; 
Specie<Dog> Bobby; 

Animal *Dingo = new Specie<Dog>(); 

Animal *Tom = new Specie<Cat>(); 

// cloning Dingo 
Animal *UnknownAnimal = Dingo->clone(); 

// We check the type is correct after cloning 
UnknownAnimal->action(); 

// We check that DoSomething recognizes correctly the type of objects 
// and uses the proper specialization 
Interaction::DoSomething(Bobby); 
Interaction::DoSomething(HelloKitty); 




// Vector of pointers to Animals 
std::vector<Animal *> myanimals; 

// We add an object of type Specie<Dog> and an object 
// of type Specie<Cat> to the vector 

myanimals.push_back(&Bobby); 
myanimals.push_back(&HelloKitty); 



Animal *UnknownAnimal2 = myanimals[1]->clone(); 

// We check the type is correct after cloning 
UnknownAnimal2->action(); 



// NOW WE TRY TO USE THE ELEMENT FROM VECTOR AS ARGUMENT OF 
// SPECIALIZED FUNCTION. DOES NOT WORK. 
Interaction::DoSomething(*(myanimals[0]->clone())); 



    return 0; 
} 

error: no instance of function template "Interaction::DoSomething" matches the argument list

argument types are: (Animal) Interaction::DoSomething(*(myanimals[0]->clone()));

什么是错在我的代码?提前致谢!

+0

'clone()'的结果仍然是'Animal *'类型,由于返回类型的协变性,它可以在子类中重写,但在基类中调用成员函数时不起作用 –

+0

除了@PiotrSkotnicki的评论:你没有'Interaction :: DoSomething'接受一个类型为'Animal'的对象 –

+0

@SimonKraemer是的,没错。我没有定义Interaction :: DoSomething(Animal),因为它只对特定的动物(狗,猫,...)有意义。交互随着每种动物类型而改变。因此我只定义了Interaction :: DoSomething(Specie )。 –

回答

0

您正在调用基类函数virtual Animal *clone() = 0;,它似乎总是返回Animal

函数重载在编译时工作,并且不能根据参数的动态类型更改调用。为此你需要虚函数调用。使用中间级的

+0

是的但是在模板类Specie中,clone()的返回类型是Specie 。这工作正常。 –

+0

@Xtof * dynamic *类型是'Specie *',但在'Animal *'上调用'clone'的* static *类型是'Animal *'。 – TartanLlama

0

可能的解决方案:

#include <iostream> 
#include <vector> 

using namespace std; 

// Base class 
class Animal { 

public: 
    virtual ~Animal() {} 
    virtual Animal *clone() = 0; 
}; 

class InteractionAnimal : public Animal { 
public: 
    virtual ~InteractionAnimal() {} 

    virtual InteractionAnimal *clone() = 0; 
    virtual void action() const = 0; 
}; 


// Specific types of animals. Forward declaration 
class Dog; 
class Cat; 



// Templated derived class Specie 
template <class T> 
class Specie : public InteractionAnimal { 

public: 
    Specie<T> *clone(); 

    void action() const; 

}; 

template <class T> 
Specie<T> * Specie<T>::clone() { 

    std::cout << "Cloning a Specie<T>" << std::endl; 
    return new Specie<T>(*this); 

} 

// Specialization of templated function action() for Dog 
template <> 
void Specie<Dog>::action() const { 

    std::cout << "Wouaf !" << std::endl; 

} 


// Specialization of templated function action() for Cat 
template <> 
void Specie<Cat>::action() const { 

    std::cout << "Miaouuu !" << std::endl; 

} 




class Interaction { 

public: 
    static void DoSomething(const InteractionAnimal& animal) { 
     //Will be called when Type is not fully known 
     animal.action(); 
    } 

}; 

int main() { 


    Specie<Cat> HelloKitty; 
    Specie<Dog> Bobby; 

    InteractionAnimal *Dingo = new Specie<Dog>(); 

    InteractionAnimal *Tom = new Specie<Cat>(); 

    // cloning Dingo 
    InteractionAnimal *UnknownAnimal = Dingo->clone(); 

    // We check the type is correct after cloning 
    UnknownAnimal->action(); 

    // We check that DoSomething recognizes correctly the type of objects 
    // and uses the proper specialization 
    Interaction::DoSomething(Bobby); 
    Interaction::DoSomething(HelloKitty); 




    // Vector of pointers to Animals 
    std::vector<InteractionAnimal *> myanimals; 

    // We add an object of type Specie<Dog> and an object 
    // of type Specie<Cat> to the vector 

    myanimals.push_back(&Bobby); 
    myanimals.push_back(&HelloKitty); 



    InteractionAnimal *UnknownAnimal2 = myanimals[1]->clone(); 

    // We check the type is correct after cloning 
    UnknownAnimal2->action(); 



    // NOW WE TRY TO USE THE ELEMENT FROM VECTOR AS ARGUMENT OF 
    // SPECIALIZED FUNCTION. DOES NOT WORK. 
    Interaction::DoSomething(*(myanimals[0]->clone())); 



    return 0; 
} 

我已删除专门DoSomething功能,因为它们将不被调用InteractiveAnimal对象。

+0

非常感谢。我试过了,即使没有中间InteractionAnimal类,它也能正常工作。我需要的是像你一样修改DoSomething,现在接受一个指向Animal *的指针作为参数,然后在里面启动适当的动作()。问题的一部分解决了。我现在需要的是在向量的两个元素之间定义一个动作,也就是说,根据两个参数的类型执行正确的动作(Animal * obj1,Animal * obj2):action(Cat,Dog);行动(猫,鸟);行动(鸟,鱼)等...... –

+0

这不适用于模板。当你只有一个“动物”对象时,你不知道对象的派生类型。 也许你应该打开另一个问题,以避免在此页面混淆。 –

+0

是的,好主意。同时我会看看双派遣可以做些什么。 –