我一直在用C ++编写一些操作文件的类。当我开始时,我让我的所有构造函数都接受一个被解释为文件名的std::string
参数,因为这很简单。
任何类使用的唯一函数std::fstream
为.open()
。我认为,由于std::ofstream
和std::ostringstream
都来自std::ostream
并且我只使用std::ostream
的函数,因此拥有每个构造函数会好得多根据需要采用std::ostream
或std::istream
参数,而不是将类绑定到文件。
一个很好的教科书例子,说明为什么多态是有用的。海湾合作委员会对此非常不满。这是我的代码的简化:
#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);
}
当使用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可能对指针更好一些,但对我来说,指向类的指针看起来像是动态分配的内存,我只想提出这些怀疑,如果它们是真的。什么是正确的方法?
答案 0 :(得分:10)
必须在constructor initialization list中初始化参考类型的成员(以及const
类型的成员):
Foo::Foo(std::istream& is) : input(is)
// ^^^^^^^^^^^
{
}
原因是您需要立即初始化引用,然后再对其执行任何其他操作。您原始代码中的内容是非法的,原因与此相同:
int y = 42;
int& x; // ERROR!
x = y;
另一方面,初始化列表保证在输入构造函数的主体之前,引用成员绑定到对象。
答案 1 :(得分:4)
将您的代码更改为以下内容:
Foo::Foo(std::istream& is) : input(is) {
}
您拥有的是作业,而不是初始化。您需要在成员初始化列表中初始化成员。
当你点击构造函数{
的主体时,所有类成员已经存在于内存中。因此,在行this->input = is;
中,您尝试将is
分配给已存在的对象,但是,必须在C ++中初始化引用,因此出现错误消息:uninitialized reference member
。
答案 2 :(得分:3)
您应该在成员初始化列表中初始化您的引用成员。
Foo::Foo(std::istream& is): input(is) {
}
无法分配C ++引用,因此必须在初始化列表中初始化它。
答案 3 :(得分:2)
改变你的构造函数
Foo::Foo(std::istream& is):input(is) {
}
错误是
error: uninitialized reference member ‘Foo::input’ [-fpermissive]
因此您必须初始化input