【发布时间】:2021-07-19 10:52:48
【问题描述】:
我有一个关于 C++、构造函数(默认和其他)、流提取运算符和引用成员变量的软件工程问题。我知道这是很多主题,但在这个问题上它们似乎都相互依赖。
对于我试图解决的问题,我想创建一个 Vec 类来保存问题的数据,以及一个 ProblemSolver 类,它最终将拥有解决问题的方法。 ProblemSolver 类没有数据就没有意义,所以我用Vec 数据的副本编写了它(参考成员的考虑后来发生了......)。所以这是我的第一个版本的样子:
#include <iostream>
#include <vector>
class Vec {
private:
std::vector<int> v;
public:
Vec(const int s) : v(s, 0) { }
};
class ProblemSolver {
private:
Vec data;
public:
ProblemSolver(Vec d) : data(d) { }
};
int main() {
int m;
std::cin >> m;
Vec v(m);
ProblemSolver ps(v);
}
到目前为止,这似乎还不错。然后我认为我应该为每个类提供流提取运算符,以便对象可以负责读取自己的数据,而不是在 main 中读取它。所以我重写了这样的类:
#include <iostream>
#include <vector>
class Vec {
private:
std::vector<int> v;
public:
Vec(const int s) : v(s, 0) { }
friend std::istream& operator >> ( std::istream& input, Vec &V ) {
int m;
input >> m;
V.v = std::vector<int>(m, 0);
return input;
}
};
class ProblemSolver {
private:
Vec data;
public:
ProblemSolver(Vec d) : data(d) { }
friend std::istream& operator >> ( std::istream& input, ProblemSolver &P ) {
input >> P.data;
return input;
}
};
int main() {
ProblemSolver p;
std::cin >> p;
}
这是我遇到一些困惑的地方,因为main() 的第一行试图调用ProblemSolver 的默认构造函数。我知道这是一个问题,因为没有提供,但是就上述问题的良好实践而言,我应该怎么做呢?我是否应该始终提供默认构造函数,即使没有实际数据集的类没有意义?我应该让对象处理自己的数据读取,而我不应该编写流提取运算符,我错了吗?
因为this article,我考虑使用引用成员变量,因为“问题解决者类的数据仍然存在于问题解决者实例存在之外”。于是我又改写成这样:
#include <iostream>
#include <vector>
class Vec {
private:
std::vector<int> v;
public:
Vec(const int s) : v(s, 0) { }
friend std::istream& operator >> ( std::istream& input, Vec &V ) {
int m;
std::cin >> m;
V.v = std::vector<int>(m, 0);
return input;
}
};
class ProblemSolver {
private:
const Vec& v;
public:
ProblemSolver(const Vec& v_) : v(v_) { }
};
int main() {
int m;
std::cin >> m;
Vec v(m);
ProblemSolver p(v);
}
但是有了这个,我仍然无法为ProblemSolver 编写流提取操作符,而为Vec 编写的操作符实际上没用,因为我必须先实例化一个Vec 对象才能使用流提取运算符。因此,在上面的示例中,我仍然需要读取main() 中的int m 数据,并且由于与第二个代码段相同的原因,我不能执行类似Vec v; std::cin >> v; ProblemSolver p(v); 的操作。我认为应该可以像 std::cin >> ProblemSolver p; 那样一次性实例化和读取变量,但显然情况并非如此。
所以我的主要问题是如何正确编写这两个类?我应该包含默认构造函数吗?我的理解是,如果类在没有任何数据的情况下没有意义,我不应该提供默认构造函数,但这是错误的吗?如果我不编写默认构造函数,我是否应该使用提供给标准构造函数的无用数据来实例化一个类,以便我可以在其上使用流提取运算符?在流提取之前错误地实例化对象似乎是一种不好的做法。
需要明确的是,我不只是在寻找可行的解决方案。我想针对此类情况开发实际的良好做法和技术,因此请以正当理由支持您的回答。
【问题讨论】:
-
流提取运算符的一个不幸的设计限制是它们仅适用于可以分配给的对象,因此如果您确定为
ProblemSolver提供它们,则无需添加默认 ctor (或其道德等价物——以某种“默认”状态构造ProblemSolver实例的某种方式,您将立即覆盖该状态)。如果您只想让ProblemSolver从流中初始化,只需添加一个直接采用std::istream的ctor。