Синтаксис C++ класса шаблона с чистой виртуальной функцией?

Я лишь поверхностно знаком с шаблонами C++, и добавление чистой виртуальной функции к классу шаблона истощило мою способность удовлетворить требования компилятора.

Следующий код...

#include <iostream>
#include <string>
#include <sstream>

class Pearl
{
    public:
        Pearl(int value);
        virtual ~Pearl();

    protected:
        int mValue;
};

Pearl::Pearl(int value)
    : mValue(value)
{
    std::cout << "$" << mValue << " Pearl created" << std::endl;
}

Pearl::~Pearl()
{
    std::cout << "$" << mValue << " Pearl destroyed" << std::endl;
}

///////////////////////////////////////////////////////////////////////

class Oyster
{
    public:
        Oyster(std::string str, int value);
        virtual ~Oyster();

    protected:
        Pearl mPearl;
        std::string mName;

    friend class OStreamer;
};

Oyster::Oyster(std::string name, int value)
    : mName(name)
    , mPearl(value)
{
    std::cout << "Oyster " << mName << " created" << std::endl;
}

Oyster::~Oyster()
{
    std::cout << "Oyster " << mName << " destroyed" << std::endl;
}

///////////////////////////////////////////////////////////////////////

template <typename T> class Streamer
{
    public:
        Streamer(T& rT, unsigned int flags);
        ~Streamer();

        virtual std::ostream Display() = 0;

        static const unsigned int A = 0x1;
        static const unsigned int B = 0x2;

    protected:
        T& mrT; // Aah pity the foo!
        unsigned int mFlags;

    friend class OStreamer;
};

///////////////////////////////////////////////////////////////////////

class OStreamer : public Streamer<Oyster>
{
    public:
        OStreamer(Oyster oyster, unsigned int flags);
        virtual std::ostream Display();
};

OStreamer::OStreamer(Oyster oyster, unsigned int flags)
    : Streamer<Oyster>(oyster, flags)
{
}

std::ostream OStreamer::Display()
{
    std::ostringstream oss;

    oss << "Oyster[" << mrT.mName << "]" << std::endl;
}

///////////////////////////////////////////////////////////////////////

template <typename T> std::ostream& operator<<(std::ostream& os, const Streamer<T> streamer)
{
    return os;
}

///////////////////////////////////////////////////////////////////////

int main()
{
    Oyster sam("Sam", 50);

    std::cout << OStreamer(sam, OStreamer::A) << std::endl;

    return 0;
}

... генерирует следующую ошибку компилятора (с g++ 4.4.7):

>g++ main.cpp
main.cpp: In function ‘int main()’:
main.cpp:107: error: cannot allocate an object of abstract type ‘Streamer<Oyster>’
main.cpp:56: note:   because the following virtual functions are pure within ‘Streamer<Oyster>’:
main.cpp:61: note:      std::ostream Streamer<T>::Display() [with T = Oyster]

Может ли кто-нибудь помочь мне понять, почему компилятор не принимает реализацию OStreamer::Display() в качестве необходимого переопределения Streamer::Display()?

Как контекст: это экспериментальный, надуманный код, чтобы ознакомиться с объединением классов шаблонов с чисто виртуальными функциями. Что я хотел бы сделать с помощью этого кода, так это реализовать оператор oream для объектов OStreamer, который вызывает OStreamer::Display. Я понимаю, что оператору ostream может потребоваться некоторая настройка, но я думаю, что проблема не в этом.


person StoneThrow    schedule 14.11.2015    source источник


Ответы (1)


Измените перегрузку оператора на:

template <typename T> std::ostream& operator<<(std::ostream& os,
                           const Streamer<T> &streamer)
{
    return os;
}

Передача параметра const Streamer<t> требует создания копии базового класса, что, конечно же, невозможно, поскольку он виртуальный.

Передача ссылки позволяет избежать этой проблемы.

person Sam Varshavchik    schedule 14.11.2015
comment
Просто ставь меня на это. +1 - person Luke Joshua Park; 14.11.2015
comment
О! Я слишком долго смотрел на код и совершенно не заметил этого. Я смиренно принимаю свое публичное смущение. :) Спасибо, @sam-varshavchik! - person StoneThrow; 14.11.2015