2013-05-15 2 views
3

Я писал несколько классов на C++, которые работают с файлами. Когда я начал, я включил все мои конструкторы в один аргумент std::string, который был интерпретирован как имя файла, потому что это было быстро и просто.Полиморфизм C++ со ссылками

Единственные функции std::fstream, которые используются в любом из классов: .open(). Я решил, что с std::ofstream и std::ostringstream оба получаются из std::ostream, и я использовал только функции std::ostream, что было бы намного лучше, если бы каждый конструктор принимал аргументили std::istream, а не ограничивал классы привязанными к файлам.

Отличный пример учебника о том, почему полиморфизм полезен. GCC довольно недоволен этим. Это упрощение моего кода:

#include <iostream> 
#include <fstream> 

class Foo { 
     public: 
       Foo(std::istream&); 
       std::istream& input; 
}; 

Foo::Foo(std::istream& is) { 
     this->input = is; 
} 

int main() { 
     std::ifstream is("test.txt"); 
     Foo foo(is); 
} 

Which, при компиляции с g++ test.cpp, производит следующий красочный ассортимент ошибок:

test.cpp: In constructor ‘Foo::Foo(std::istream&)’: 
test.cpp:10:1: error: uninitialized reference member ‘Foo::input’ [-fpermissive] 
In file included from /usr/include/c++/4.7/ios:43:0, 
       from /usr/include/c++/4.7/ostream:40, 
       from /usr/include/c++/4.7/iostream:40, 
       from test.cpp:1: 
/usr/include/c++/4.7/bits/ios_base.h: In member function ‘std::basic_ios<char>& std::basic_ios<char>::operator=(const std::basic_ios<char>&)’: 
/usr/include/c++/4.7/bits/ios_base.h:791:5: error: ‘std::ios_base& std::ios_base::operator=(const std::ios_base&)’ is private 
In file included from /usr/include/c++/4.7/ios:45:0, 
       from /usr/include/c++/4.7/ostream:40, 
       from /usr/include/c++/4.7/iostream:40, 
       from test.cpp:1: 
/usr/include/c++/4.7/bits/basic_ios.h:64:11: error: within this context 
In file included from /usr/include/c++/4.7/iostream:41:0, 
       from test.cpp:1: 
/usr/include/c++/4.7/istream: In member function ‘std::basic_istream<char>& std::basic_istream<char>::operator=(const std::basic_istream<char>&)’: 
/usr/include/c++/4.7/istream:56:11: note: synthesized method ‘std::basic_ios<char>& std::basic_ios<char>::operator=(const std::basic_ios<char>&)’ first required here 
test.cpp: In constructor ‘Foo::Foo(std::istream&)’: 
test.cpp:11:16: note: synthesized method ‘std::basic_istream<char>& std::basic_istream<char>::operator=(const std::basic_istream<char>&)’ first required here 

У меня проблемы просеивания через все аргументы шаблона, но это выглядит ему не нравится this->input = is;. Для каждого класса важно иметь доступ к потоку в качестве члена, потому что различные функции-члены должны иметь возможность его видеть. Я полагал, что GCC, вероятно, будет лучше об указателе, но для меня указатели на классы выглядят подозрительно, как динамически распределенная память, и я хочу только поднять эти подозрения, если они верны. Каков правильный путь?

ответ

10

Члены ссылочного типа (а также члены const типа) должны быть инициализированы в constructor initialization list:

Foo::Foo(std::istream& is) : input(is) 
//       ^^^^^^^^^^^ 
{ 
} 

Причина заключается в том, что вы немедленно должны инициализировать ссылку, прежде чем делать что-нибудь еще с этим. Что вы имеете в исходном коде, является незаконным по той же причине, почему это является незаконным:

int y = 42; 
int& x; // ERROR! 
x = y; 

списков инициализации, с другой стороны, гарантирует, что ваш контрольный элемент привязан к объекту перед тем ТЕЛА вводится конструктор.

+0

Хорошая связь и хорошее объяснение, именно то, что я искал. – Monchoman45

+0

@ Monchoman45: Рад, что это помогло;) –

4

Измените код следующим образом:

Foo::Foo(std::istream& is) : input(is) { 
} 

Что у вас есть это назначение, не инициализации. Вы должны инициализировать член в списке инициализации члена.

К тому времени, когда вы нажмете тело конструктора {, все члены класса уже существуют в памяти. Итак, в строке this->input = is; вы пытаетесь назначить is уже существующему объекту, однако ссылки должны быть инициализированы в C++, поэтому сообщение об ошибке: uninitialized reference member.

3

Вы должны инициализировать свой ссылочный элемент в списке инициализации членов.

Foo::Foo(std::istream& is): input(is) { 
} 

Ссылка на C++ не может быть назначена, поэтому она должна быть инициализирована в списке инициализации.

2

изменить конструктор это это

Foo::Foo(std::istream& is):input(is) { 

} 

ошибка

error: uninitialized reference member ‘Foo::input’ [-fpermissive] 

так что вы должны инициализировать input

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