ostream в классе не имеет типа

Только что изучил C ++, и у меня быстрый вопрос.

После компиляции с

g++ *.cpp -o output

Я получаю такую ​​ошибку:

error: 'ostream' in 'class Dollar' does not name a type

Это мои три файла:

main.cpp

#include <iostream>
#include "Currency.h"
#include "Dollar.h"

using namespace std;

int main(void) {
    Currency *cp = new Dollar;

    // I want this to print "printed in Dollar in overloaded << operator"
    cout << cp;
    return 0;
}

Dollar.cpp

#include <iostream>
#include "Dollar.h"

using namespace std;

void Dollar::show() {
    cout << "printed in Dollar";
}

ostream & operator << (ostream &out, const Dollar &d) {
    out << "printed in Dollar in overloaded << operator";
}

Dollar.h

#include "Currency.h"

#ifndef DOLLAR_H
#define DOLLAR_H

class Dollar: public Currency {
    public:
        void show();
};

ostream & operator << (ostream &out, const Dollar &d);

#endif

Спасибо за уделенное время, все помогает!


person Kyle    schedule 16.01.2018    source источник
comment
Он называется std::ostream.   -  person juanchopanza    schedule 17.01.2018
comment
Используйте 1_. Не используйте using namespace std;.   -  person Ron    schedule 17.01.2018
comment
Так что удалите using namespace std в моем файле Dollar.cpp?   -  person Kyle    schedule 17.01.2018
comment
и добавить std: ostream в мои файлы .cpp и .h?   -  person Kyle    schedule 17.01.2018
comment
Скорее всего, не будет работать и строка компиляции. См. это сообщение SO по этому вопросу.   -  person Ron    schedule 17.01.2018
comment
Несвязанный: обычно лучше всего поместить весь заголовок внутри защиты заголовка. В Dollar.h я рекомендую переместить #include "Currency.h" на после #define DOLLAR_H   -  person user4581301    schedule 17.01.2018


Ответы (2)


У вас есть ряд ошибок в коде.

  1. Вы активно используете using namespace std. Это плохая практика. В частности, это привело к ошибке, с которой вы столкнулись: у вас нет using namespace std в Dollar.h, поэтому компилятор не знает, что означает ostream. Либо поместите using namespace std в Dollar.h, либо лучше просто прекратите его использовать и напрямую укажите пространство имен std, как в std::ostream.
  2. Вы используете std::ostream в своих заголовках, но не включаете в них соответствующий заголовок стандартной библиотеки <ostream> (<ostream> содержит определение класса std::ostream; для полной библиотеки ввода-вывода включите <iostream>). Действительно хорошая практика - включить все зависимости заголовка в сам заголовок, чтобы он был самодостаточным и мог быть безопасно включен где угодно.
  3. Вы реализуете оператор вывода потока с подписью std::ostream & operator << (std::ostream &, Dollar const &), что совершенно верно. Однако вы вызываете его для указателя, чтобы ввести Dollar. Вы должны вызывать его с помощью самого объекта, а не указателя, поэтому вам следует разыменовать указатель: std::cout << *cp;.
  4. Вы реализовали оператор вывода для класса Dollar, но используете его для переменной типа Currency: это не сработает. Есть способ сделать это - именно по этой причине существуют виртуальные методы. Однако в этом случае оператор является бесплатной функцией, поэтому он не может быть виртуальным. Итак, вам, вероятно, следует добавить виртуальный метод print в свой класс Currency, реализовать его в Dollar и вызвать его из оператора вывода:

    #include <iostream>
    
    class Currency {
    public:
        virtual void print (std::ostream &) const = 0;
    };
    
    class Dollar : public Currency {
        void print (std::ostream & out) const override {
            out << "A dollar";
        }
    };
    
    std::ostream & operator << (std::ostream & out, Currency const & c) {
        c.print(out);
        return out;
    }
    
    int main(/* void is redundant here */) {
        Currency *cp = new Dollar;
        std::cout << *cp;
        // return 0 is redundant in main
    }
    
person lisyarus    schedule 16.01.2018
comment
Вы используете std :: ostream в своих заголовках, но не включаете соответствующий заголовок стандартной библиотеки ‹iostream› - Соответствующий стандартный заголовок - <ostream>. Нет необходимости загружать полную библиотеку потоков ввода-вывода. - person zett42; 17.01.2018
comment
@ zett42 Вы правы, спасибо! Я обновлю ответ. - person lisyarus; 17.01.2018

Вам нужно #include <iostream> в Dollar.h, чтобы ваш std::ostream & operator был разрешен компилятором.

person Justin Randall    schedule 16.01.2018
comment
В показанном коде в этом нет необходимости. Но OP действительно должен называть это std::ostream. - person juanchopanza; 17.01.2018
comment
@juanchopanza, почему ты так говоришь? Я не вижу этому свидетельств. - person SergeyA; 17.01.2018
comment
@SergeyA, он полагается на то, что iostream был включен в main.cpp и Dollar.cpp до Dollar.h. Обратите внимание, что я не говорю, что включение не следует добавлять, но в данном случае это не является источником ошибки. - person juanchopanza; 17.01.2018
comment
@juanchopanza, да, вы правы, пропустил этот порядок включения в main. - person SergeyA; 17.01.2018