2015-08-26 63 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

是的,好主意。同時我會看看雙派遣可以做些什麼。 –