2012-01-09 3 views
2

iostream и другой класс потока - нет действительно класс, но typedef s, правый?не может назначить или скопировать объект iostream?

Вот проблема, я пытался инициализировать istream объект в списке инициализации, но, к сожалению, я получил сообщение об ошибке, код идет ниже:

class A 
{ 
    public: 
     A(istream &is=cin): ais(is) 
     {} 

    private: 
     istream ais; 
}; 

Не удается скомпилировать с г ++, ошибка:

synthesized method ‘std::basic_istream<char, std::char_traits<char> >::basic_istream(const std::basic_istream<char, std::char_traits<char> >&)’ first required here 

Я искал SO, нашел, что iostream cannot be assigned or copy. Но почему я не могу инициализировать его в списке инициализации ?

Cuz Я думаю, список инициализации вызовет конструктор объекта/copy-constructor, правильно?

ответ

6

Ваш код пытается превратить один istream, тот, который передан конструктору, на два istream s, тот, который был передан конструктору и ais. Объект istream представляет собой фактический поток. Существует только один поток, и нет способа каким-то образом превратить его в два потока.

Даже не ясно, что это будет означать. Если в потоке есть какие-то данные, независимо от того, какой поток читает, сначала получите его? Или они оба это получают? Если да, кто или что его дублирует?

istream как файл сам. Вы не можете превратить один файл в два файла без копирования данных от одного к другому самостоятельно. Однако вы можете иметь столько ссылок или указателей на то же самое istream, сколько хотите. Решение вашей проблемы, вероятно, должно сделать ссылку ais.

+0

Я понял, спасибо. :) – Alcott

3

iostream and other stream class are not actually class, but typedefs, right?

Да, но это не имеет отношения к делу.

But why cannot I initialize it in the initialization list?

Потому что он не может быть ни скопирован, ни назначен. Ctor init список не волшебный. Чтобы создать ais от is, вам необходимо сделать копию, и вы не можете.

4

У вас есть переменная-член объявлена ​​как:

istream ais; 

означает, конструктор копирования будет вызван в списке инициализаторов. Это не относится к списку инициализаторов: вы ничего не можете сделать.

Вы можете изменить переменную-член, чтобы быть ссылка:

istream& ais; 

, но это означает, что вы должны убедиться, что istream, к которому относится ais действительна в течение всего срока службы A.

1

В дополнение к ответам вы уже получили, вы можете также инициализировать ais (по вашему определению) с streambuf потока, переданному в (конечно, то же самое предостережение, как со ссылкой применяется: Вы должны убедитесь, что streambuf остается действительным до тех пор, пока объект не будет уничтожен).

Инициализация базовым потоковым буфером, вероятно, наиболее близка к копированию потока, который вы можете сделать: хотя оба устройства по-прежнему считываются из одного и того же файла и используют ту же буферизацию (и другую обработку, которую может выполнять streambuf), все форматирование и обработка ошибок флаги являются отдельными.

Для инициализации ais с streambuf, вы пишете:

class A 
{ 
public: 
    A(std::istream& is = std::cin): 
    ais(is.rdbuf()) 
    { 
    } 
private: 
    std::istream ais; 
}; 
2

Объект потока представляет дескриптор потоков данных. Копирование этого не имеет смысла. Кроме того, было бы нецелесообразно копировать только базовую часть tge потока: это отсекало бы интересный бит (хотя вы могли бы получить интересную часть, используя буфер потока).

Что вы хотите инициализировать в своем классе, если он держит поток является ссылка на поток:

std::istream& ais; 

Конечно, это означает, что некоторые внешние потребности, чтобы сохранить поток в живых до тех пор, пока вы используй это. Если это не то, что вам нужно или нужно, вы можете провести свой класс, например. std::ifstream и возьмите std::string как аргумент конструктора: если строка не пуста, вы откроете соответствующий файл. В противном случае вы бы установить с std::cin ваш ручья rdbuf() к одному:

if (name.empty()) 
    ais.open(name.c_str()); 
else 
    ais.rdbuf(std::cin.rdbuf()); 
+0

На самом деле, если бы он представлял ручку, копирование было бы идеальным. Нет причин, по которым вы не можете иметь две ручки для одного потока данных. Проблема состоит в том, что он представляет сам поток *. И есть только один поток данных. –

+0

Думаю, я так сказал. Интересно, что 'std :: istream' фактически ** является ** главным образом дескриптором для' std :: streambuf'. Однако производный тип фактически владеет и внедряет конкретный буфер потока. –

+0

Я думаю, что это более «контейнер», чем «ручка». Термин «ручка» несет много багажа, что делает его похожим на файлы или ручки. –

1
class A 
{ 
    public: 
     A(istream &is=cin): ais(is) 
     {} 

    private: 
     istream& ais; 
}; 

Уведомление элемент является ссылочным типом. Когда вы его написали, вы делаете копию для инициализации члена.