初始化头文件v/s源文件中的std::ofstream对象



我遇到了一些与std::ofstream相关的奇怪编译错误。比方说,我有一个头文件ofstream_test.hpp,和它对应的源文件ofstream_test.cpp

ofstream_test.hpp:

#include <iostream>
#include <fstream>
class OfstreamTest {
public:
OfstreamTest();
std::ofstream m_strm_obj("output.txt");
};

ofstream_test.cpp:

#include "ofstream_test.hpp"
OfstreamTest::OfstreamTest() {
std::cout << "ctor" << std::endl;
}

main.cpp:

#include "ofstream_test.hpp"
int main(int argc, char const *argv[]) {
OfstreamTest obj;
return 0;
}

错误:

$ g++ -std=c++17 main.cpp ofstream_test.cpp 
In file included from main.cpp:1:0:
ofstream_test.hpp:8:30: error: expected identifier before string constant
std::ofstream m_strm_obj("output.txt");
^~~~~~~~~~~~
ofstream_test.hpp:8:30: error: expected ‘,’ or ‘...’ before string constant
In file included from ofstream_test.cpp:1:0:
ofstream_test.hpp:8:30: error: expected identifier before string constant
std::ofstream m_strm_obj("output.txt");
^~~~~~~~~~~~
ofstream_test.hpp:8:30: error: expected ‘,’ or ‘...’ before string constant

如果我尝试使用open方法,我也会得到编译错误(虽然有点不同):

ofstream_test.hpp:

class OfstreamTest {
public:
OfstreamTest();
std::ofstream m_strm_obj;
m_strm_obj.open("output.txt");
};

ofstream_test.cpp:

OfstreamTest::OfstreamTest() {
std::cout << "ctor" << std::endl;
}

错误:

$ g++ -std=c++17 main.cpp ofstream_test.cpp 
In file included from main.cpp:1:0:
ofstream_test.hpp:9:5: error: ‘m_strm_obj’ does not name a type
m_strm_obj.open("output.txt");
^~~~~~~~~~
In file included from ofstream_test.cpp:1:0:
ofstream_test.hpp:9:5: error: ‘m_strm_obj’ does not name a type
m_strm_obj.open("output.txt");
^~~~~~~~~~

然而,对于以下情况,我没有得到任何编译错误:

  • 案例1:
class OfstreamTest {
public:
OfstreamTest();
};
OfstreamTest::OfstreamTest() {
std::cout << "ctor" << std::endl;
std::ofstream m_strm_obj("output.txt");  // initialized the object in source file, instead of header file
}
  • 案例2:
class OfstreamTest {
public:
OfstreamTest();
std::ofstream m_strm_obj{"output.txt"};  // just changed () to {}
};
OfstreamTest::OfstreamTest() {
std::cout << "ctor" << std::endl;
}
  • 案例3:
class OfstreamTest {
public:
OfstreamTest();
std::ofstream m_strm_obj;  // declared the object but didn't initialize in the header file
};
OfstreamTest::OfstreamTest() {
std::cout << "ctor" << std::endl;
m_strm_obj.open("output.txt");
}

我不明白为什么?

将非常感谢一个深入的答案(或至少有一些参考链接的答案)!

std::ofstream m_strm_obj("output.txt");在将m_strm_obj声明为类成员时是无效的语法(将其声明为局部变量时是可以的)。

你不能初始化/构造一个类数据成员(不管它的类型),在类范围内声明成员的地方用括号括起来。c++标准的语法规则根本不允许这样做,以避免将编译器与成员函数声明混淆。

但是,从c++ 11开始,可以在类作用域使用花括号初始化/构造类数据成员,例如:

class OfstreamTest {
public:
OfstreamTest();
std::ofstream m_strm_obj{"output.txt"};
};

否则,可以使用父类构造函数的成员初始化列表,例如:

class OfstreamTest {
public:
OfstreamTest();
std::ofstream m_strm_obj;
};
OfstreamTest::OfstreamTest() : m_strm_obj("output.txt") {
std::cout << "ctor" << std::endl;
}

,或者在构造函数体内使用open(),例如:

class OfstreamTest {
public:
OfstreamTest();
std::ofstream m_strm_obj;
};
OfstreamTest::OfstreamTest() {
std::cout << "ctor" << std::endl;
m_strm_obj.open("output.txt");
}

最新更新