默认成员值最佳实践
Posted
技术标签:
【中文标题】默认成员值最佳实践【英文标题】:Default member values best practice 【发布时间】:2012-07-20 15:28:42 【问题描述】:编写 C++11 代码在类的头文件中为类成员设置默认值是一种好习惯吗?
或者在类的构造函数中这样做更好?
编辑:
我的意思是:
foo.h:
#include <string>
using std::string;
class Foo
private:
string greet = "hello";
public:
Foo();
;
VS
foo.cpp(当然有必要的头文件,但没有类内初始化):
Foo::Foo()
greet = "hello";
哪个更好,为什么?
【问题讨论】:
头文件是什么意思? C ++ 11类内成员初始化?这两种情况的代码示例将有助于说明。 @chris 更新了代码示例。 这两个样本做不同的事情,所以肯定第一个更好。搜索成员初始化列表 应避免在标题中使用子句 有点晚了,我知道——你应该使用构造函数初始化列表:Foo::Foo() : greet("hello")
——这避免了默认初始化+赋值,而是直接按值初始化。对于复杂类型,这可能会产生显着差异,但更重要的是:某些类型(引用、常量成员、非默认可构造的)只有可以这样初始化(在构造函数中,除了分配一个默认值)。
【参考方案1】:
这取决于您是否需要与旧的 C++ 编译器保持兼容。当您不使用 C++11 时,您必须在构造函数中初始化大多数成员(所有成员都是非静态的)。 此外,许多人主张显式初始化每个成员,即使这意味着显式调用默认 ctor。 通常你应该把实现细节放在一个cpp文件中而不是头文件中,因此一个例子是
Example:
//foo.h
class Foo
public:
Foo();
private:
std::vector<int> vect;
;
//foo.cpp
Foo::Foo():vect()
在 C++11 中,您有更多选择,并且在类成员初始化程序中将变得非常方便,尤其是在您有多个 cors 的情况下。这是一个很好的链接以获取更多信息:http://www.stroustrup.com/C++11FAQ.html#member-init
编辑后:根据您的代码,您使用的是 C++11。据我所知,关于新可能性的良好实践信息很少,但恕我直言,在类成员初始化程序中非常方便地将初始化集中在一个地方,从而降低了复杂性和打字
【讨论】:
是的,我更新了我的问题以更好地反映我的意思,我基本上同意你关于“减少复杂性和打字”的观点。【参考方案2】:如果一个类成员总是用相同的初始值初始化,那么你应该使初始化器内联,以避免重复。如果初始值依赖于构造函数,则将其放入构造函数初始化列表中。 (并且永远不要像以前那样使用赋值。)
例子:
class Foo
bool done = false; // always start like this
int qty;
Bar * p;
public:
Foo() : qty(0), p(nullptr)
Foo(int q, Bar * bp) : qty(q), p(bp)
explicit Foo(char const * s) : qty(std::strlen(s)), p(new Bar(s))
// ...
;
在这个假设的例子中,成员done
总是要求以false
开头,所以最好内联编写初始化程序。另外两个成员,qty
和 p
,可以在三个不同的构造函数中进行不同的初始化,因此它们在构造函数的初始化列表中进行初始化。
A curiosum:请注意,提供内联初始化程序会阻止您的类拥有平凡的默认构造函数。
【讨论】:
您还可以使用构造函数委托来避免冗余。 "永远不要像以前那样使用赋值。"我认为解释为什么永远不应该这样做是对您答案的一个很好的补充。 @cp.engr:因为你通常应该初始化,而不是重新分配。 @KerrekSB Paul 使用的作业和您使用的作业有什么区别?两者都将成员变量分配给一个值。 @JossieCalderon:我从不使用赋值 :-)【参考方案3】:在标头中初始化的主要优点是使代码更加本地化且易于理解。它还节省了一些打字。
在我看来,主要缺点是需要包含更多标头才能访问构造函数。简单的前向声明是不够的,会导致编译时间更长。
【讨论】:
以上是关于默认成员值最佳实践的主要内容,如果未能解决你的问题,请参考以下文章