在C++ 11之前,您没有非静态成员初始化,也没有构造委派,因此人们经常使用私有帮助函数来帮助初始化以减少代码复制.
这是2018年的好代码吗?
class A {
int a1 = 0;
double a2 = 0.0;
string a3 = "";
unique_ptr<DatabaseHandle> upDBHandle;
void init(){
upDBHandle = open_database(a1, a2, a3);
}
public:
A() { init(); }
explicit A(int i):a1(i) { init(); }
explicit A(double d):a2(d) { init(); }
explicit A(std::string s):a3(std::move(s)) { init(); }
A(int i, double d, std::string s) : a1(i), a2(d), a3(std::move(s)) { init(); }
};
Run Code Online (Sandbox Code Playgroud)
如何改进此代码?
在我看来,你的代码很好。我尽量避免依赖微妙的效果,例如构造函数初始化列表中的成员初始化顺序。它违反了 DRY - 您需要重复使用相同的顺序:在声明成员时在类体中,以及在构造函数初始化列表中。随着时间的流逝,类变得更大,并且您将构造函数移到.cpp文件中,事情开始变得更加混乱。因此,我将需要访问其他成员的东西放入init函数中。
如果成员是const,则不能执行此操作。但话又说回来,作为类作者,您可以决定哪个成员是 const,哪个不是。请注意,这不要与“构造,然后初始化”的反模式混淆,因为这里init发生在构造函数中,而这对类用户是不可见的。
如果您仍然不喜欢使用init,我建议不要将调用放入构造函数初始化列表中。也许对我来说,一个可接受的中途是将它放入类内初始化程序中,并从构造函数中删除所有调用。
class A {
int a1 = 0;
double a2 = 0.0;
string a3 = "";
unique_ptr<DatabaseHandle> upDBHandle = open_database(a1, a2, a3);
// ...
Run Code Online (Sandbox Code Playgroud)
C++ 不太擅长处理多个默认值。因此,要做好这件事并不容易。您可以执行多种操作,但所有操作都有不同的权衡(例如,分散默认值)。
恕我直言,这里可以找到的最好的解决方案,虽然还不是合法的 C++,但它是一个高度支持的扩展:指定的初始值设定项。
class A {
struct Params {
int a1 = 0;
double a2 = 0.0;
string a3 = "";
};
Params p;
unique_ptr<DatabaseHandle> upDBHandle;
public:
explicit A(Params p_arg)
: p(std::move(p_arg))
, upDBHandle(open_database(p.a1, p.a2, p.a3) { }
};
A a({}); // uses all defaults
A a2({.a2 = 0.5}); // specifies a2 but leaves a1 and a3 at default
A a3({.a1 = 2, .a2=3.5, .a3 = "hello"}); // specify all
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
487 次 |
| 最近记录: |