2015-11-03 3 views
0

Я пытаюсь перегрузить оператор < < для шаблона класса, но компилятор дает мне ошибку компоновщика. Цель состоит в том, чтобы иметь возможность отправить указатель базового класса с ссылкой на std :: cout так, чтобы вызываемый производный оператор < <.Шаблоны и оператор перегрузки <<

Возможно ли это?

class IBase 
{ 
public: 
    IBase() {}; 
    virtual ~IBase() {}; 
}; 

template <typename T> 
class Derived 
    : public IBase 
{ 
public: 
    Derived(T data); 
    friend std::ostream& operator<<(std::ostream& os, const Derived<T>& dt); 
private: 
    T data_; 
}; 

template <typename T> 
Derived<T>::Derived(T data) 
    : IBase(), 
     data_(data) 
{ 
} 

template <typename T> 
std::ostream& operator<<(std::ostream& os, const Derived<T>& dt) 
{ 
    os << dt.data_; 
    return os; 
} 


int _tmain(int argc, _TCHAR* argv[]) 
{ 


    // Question 1 
    Derived<int> der(234); 
    std::cout << der; 

    // Question 2 
    //IBase* base = new Derived<int>(5); 
    // std::cout << *base 
} 

Вот ошибки:

ошибка LNK2001: неразрешенный внешний символ «класса станд :: basic_ostream> & __cdecl оператор < < (класс станд :: basic_ostream

&, класс Производный const &) "(?? 6 @ YAAAV? $ Basic_ostream @ DU? $ Char_traits @ D @ std @@@ st ? D @@ AAV01 @ ABV $ производный @ H @@@ Z)

и

фатальным LNK1120 ошибки: 1 неразрешенных внешних

ответ

2

Вы должны declarate оператор друга в качестве шаблона слишком

template<typename T1> 
friend std::ostream& operator<<(std::ostream& os, const Derived<T1>& dt); 
+0

Спасибо! Это сделало трюк –

0

заменить

friend std::ostream& operator<<(std::ostream& os, const Derived<T>& dt); 

с

template<typename D> 
friend std::ostream& operator<<(std::ostream& os, const Derived<D>& dt); 
0

Вашей насущной проблемой является то, что оператор должен быть шаблонным.

Однако ваша конечная цель не может быть достигнута с помощью шаблонов в качестве разыменования IBase* получает вас IBase& - экземпляр шаблона возникает во время компиляции, и компилятор не имеет доступа к типу времени выполнения.

Таким образом, ваш шаблонный оператор никогда не будет использоваться, если вы передадите разыменованный IBase* на номер operator <<.

Вместо этого добавьте виртуальную функцию вывода на базу и заменить его:

class IBase 
{ 
public: 
    IBase() {}; 
    virtual ~IBase() {}; 
    virtual std::ostream& output(std::ostream&) const = 0; 
}; 

template <typename T> 
class Derived 
    : public IBase 
{ 
public: 
    Derived(T data); 
    virtual std::ostream& output(std::ostream& os) const 
    { 
     os << data; 
     return os; 
    } 
private: 
    T data_; 
}; 

std::ostream& operator<<(std::ostream& os, const IBase& dt) 
{ 
    return dt.output(os); 
} 
+0

Спасибо за это! Я спросил об этом как отдельный вопрос несколько минут назад, пожалуйста, напишите свой ответ там, чтобы я мог его принять. http://stackoverflow.com/questions/33496137/virtual-operator-and-templates –

0

Вам не нужно, чтобы сделать ваш friend шаблон:

friend std::ostream& operator<<(std::ostream& os, const Derived<T>& dt); 

Это должно быть изменено :

friend std::ostream& operator<< <>(std::ostream& os, const Derived<T>& dt); 

operator<< функция должна быть видимо перед объявлением friend, чтобы эта форма работала.

Вы должны предпочесть эту форму для создания шаблона friend, потому что вам не нужно, чтобы все экземпляры оператора составляли friend s, только один из них.

2

friend std::ostream& operator<<(std::ostream& os, const Derived<T>& dt);

объявляет нон шаблон версии friend, поэтому вы должны реализовать

std::ostream& operator<<(std::ostream& os, const Derived<T>& dt); 

для каждого T вы используете:

std::ostream& operator<<(std::ostream& os, const Derived<int>& dt) { 
    return os << dt.data_; 
} 

И так далее. способ сделать это без дублирования кода с определением внутри класса:

template <typename T> 
class Derived : public IBase 
{ 
public: 
    explicit Derived(T data); 
    friend std::ostream& operator<<(std::ostream& os, const Derived<T>& dt) 
    { 
     return os << dt.data_; 
    } 
private: 
    T data_; 
}; 

Demo

Другим вариантом является сделать шаблон функции.

// Forward declarations 
template <typename T> class Derived; 
template <typename T> std::ostream& operator<<(std::ostream& os, const Derived<T>& dt); 

А потом в Derived, у вас есть 2 варианта:

  • объявляем каждый Друг метод шаблона:

    template <typename T2> 
    friend std::ostream& operator<<(std::ostream& os, const Derived<T2>& dt); 
    

    Так std::ostream& operator<<(std::ostream& os, const Derived<int>& dt) имеет доступ к закрытым членам Derived<int>, но и до Derived<char>

    Demo

  • Declare только шаблон, который совпадает с аргументом:

    friend std::ostream& operator<< <>(std::ostream& os, const Derived& dt); 
    

    и так std::ostream& operator<<(std::ostream& os, const Derived<int>& dt) не имеет доступа к закрытым членам Derived<char>.

    Demo

Смежные вопросы