簡體   English   中英

調用派生類型的模板化函數

[英]Calling the templated function of a derived type

我正在嘗試對該值調用模板化函數,但我想調用來自潛在派生類型的函數的模板化版本。 正在確定類型是Dogtypeid期間,但任何typeid嘗試都失敗了。 如何調用派生類型模板化的WriteData函數?

關於例子

  1. WriteData函數是模板化的,即使在這個例子中沒有使用該值,因為我做了一個小例子。
  2. 並不總是知道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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM