![](/img/trans.png)
[英]“template polymorphism” when calling function for templated parameter of base type, with derived type?
[英]Calling the templated function of a derived type
我正在嘗試對該值調用模板化函數,但我想調用來自潛在派生類型的函數的模板化版本。 正在確定類型是Dog
在typeid
期間,但任何typeid
嘗試都失敗了。 如何調用派生類型模板化的WriteData
函數?
關於例子
WriteData
函數是模板化的,即使在這個例子中沒有使用該值,因為我做了一個小例子。Array
參數將是一個Animal
。#include <iostream>
using namespace std;
struct Writer {
void Write(char* data) {
cout << data << endl;
}
};
template<typename Type>
struct Array {
Type Data[2];
template<typename Formatter>
void WriteData(Formatter formatter) {
cout << "Data[0](typeid): " << typeid(*Data[0]).name() << endl;
cout << "Data[1](typeid): " << typeid(*Data[1]).name() << endl;
Data[0]->WriteData(formatter); // "Animal is doing something"
Data[1]->WriteData(formatter); // "Dog is doing something"
auto data1cast = reinterpret_cast<decltype(Data[1])>(Data[1]);
cout << "data1cast(typeidformatter " << typeid(*data1cast).name() << endl; // data1cast(typeid): class Dog
(*data1cast).WriteData(formatter); // "Animal is doing something"
((Dog*)Data[1])->WriteData(formatter); // "Dog is doing something"
}
};
struct Animal {
virtual ~Animal() = default;
template<typename Formatter>
void WriteData(Formatter formatter) {
formatter.Write("Animal is doing something");
}
};
struct Dog : Animal {
template<typename Formatter>
void WriteData(Formatter formatter) {
formatter.Write("Dog is doing something");
}
};
int main(void) {
Array<Animal*> arr;
arr.Data[0] = new Animal();
arr.Data[1] = new Dog();
Writer writer;
arr.WriteData(writer);
system("PAUSE");
return 0;
}
輸出
Data[0](typeid): struct Animal
Data[1](typeid): struct Dog
Animal is doing something
Animal is doing something
data1cast(typeid): struct Dog
Animal is doing something
Dog is doing something
模板和虛擬不能混合:
template<typename Formatter>
virtual void WriteData(Formatter formatter);
將是無效的聲明。
成員函數模板不能是虛擬的,派生類中的成員函數模板不能覆蓋基類中的虛擬成員函數。
您在此處有多種選擇,具體取決於您想要實現的靈活性以及您擁有的其他限制。 例如:
1.
您可以引入一個抽象類Formatter
:
struct Formatter {
virtual ~Formatter() = default;
virtual void Write(const std::string&) = 0;
};
struct Writer : Formatter {
void Write(const std::string& data) override {
std::cout << data << std::endl;
}
};
並使WriteData
成為非模板:
struct Animal {
virtual ~Animal() = default;
virtual void WriteData(Formatter& formatter) {
formatter.Write("Animal is doing something");
}
};
struct Dog : Animal {
void WriteData(Formatter& formatter) override {
formatter.Write("Dog is doing something");
}
};
2.
使WriteData
成為調用虛擬成員函數以獲取應傳遞給Formatter
信息的非虛擬模板:
struct Writer {
template<class T>
void Write(const T& data) {
std::cout << data << std::endl;
}
};
struct Animal {
virtual ~Animal() = default;
template<class Formatter>
void WriteData(Formatter formatter) {
formatter.Write(MyName() + " is doing something");
}
virtual std::string MyName() {
return "Animal";
}
};
struct Dog : Animal{
virtual std::string MyName() {
return "Dog";
}
};
3.
根本不要使用虛擬,在編譯時調度WriteData
調用。 使用std::tuple
代替數組來存儲不同的類型:
struct Writer {
template<class T>
void Write(const T& data) {
std::cout << data << std::endl;
}
};
template<typename... Types>
struct Array {
std::tuple<Types...> Data;
Array(Types... data) : Data(std::move(data)...) {}
template<typename Formatter>
void WriteData(Formatter formatter) {
std::get<0>(Data).WriteData(formatter);
std::get<1>(Data).WriteData(formatter);
}
};
struct Animal {
template<typename Formatter>
void WriteData(Formatter formatter) {
formatter.Write("Animal is doing something");
}
};
struct Dog { // can be derived from Animal, but here it doesn't matter
template<typename Formatter>
void WriteData(Formatter formatter) {
formatter.Write("Dog is doing something");
}
};
int main() {
Array<Animal, Dog> arr{Animal(), Dog()}; // <...> can be omitted in C++17
Writer writer;
arr.WriteData(writer);
}
4.
您可以在if-else
分支中使用dynamic_cast
:
struct Writer {
template<class T>
void Write(const T& data) {
std::cout << data << std::endl;
}
};
struct Animal {
virtual ~Animal() = default;
template<typename Formatter>
void WriteData(Formatter formatter) {
formatter.Write("Animal is doing something");
}
};
struct Dog : Animal {
template<typename Formatter>
void WriteData(Formatter formatter) {
formatter.Write("Dog is doing something");
}
};
template<typename Type>
struct Array {
Type Data[2];
template<typename Formatter>
void WriteData(Formatter formatter) {
for (auto d : Data) {
if (auto dog = dynamic_cast<Dog*>(d))
dog->WriteData(formatter);
else
d->WriteData(formatter);
}
}
};
這個設計非常糟糕。 每次修改動物的層次結構時,都必須更新Array::WriteData
。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.