结构的构造函数,不执行任何操作

coo*_*roc 17 c++ constructor struct

编辑:为了清楚,结构没有做任何事情,因为它没有任何功能.我想我给人的印象是我认为使用初始化列表并将构造函数的主体留空是问题.

假设我使用结构来保存两个值,我有一个构造函数,所以我可以创建一个像这样的任意结构:

struct twoValues
{
    int x;
    int y;

    twoValues(int x_, int y_):y(y_),x(x_)
    {}
};

someFunction(twoValues(1,2));
Run Code Online (Sandbox Code Playgroud)

这使我不必这样做:

twoValues anInstance;
anInstance.x=1;
anInstance.y=2;
someFunction(anInstance);
Run Code Online (Sandbox Code Playgroud)

编辑:你们都是正确的,我也可以用以下内容初始化:

twoValues anInstance = {1,2};
Run Code Online (Sandbox Code Playgroud)

我认为没有错,但我从C++测试得到了一些反馈,其中一个负反馈标记是"没有做任何事情的结构的构造函数".我与测试我的人接触有限,因此从未问过为什么.

这是一件坏事,为什么?我宁愿继续这样做.

Jam*_*nze 17

这取决于结构的用途.正如其他人所说,构造函数意味着该类不再是POD,并且聚合初始化不能用于它.特别是,您不能在命名空间范围内拥有某些内容,例如:

TwoValues const table[] =
{
    { 1, 2 },
    { 3, 4 },
    // ...
};
Run Code Online (Sandbox Code Playgroud)

你可以有:

TwoValues const table[] =
{
    TwoValues(  1, 2  ),
    TwoValues(  3, 4  ),
    // ...
};
Run Code Online (Sandbox Code Playgroud)

但它更冗长,它意味着动态初始化,这可能导致初始化问题的顺序.

另一方面,如果没有构造函数,则无法动态创建临时实例.代替:

extern void f( TwoValues const& );
//  ...

f( TwoValues( 1, 2 ) );
Run Code Online (Sandbox Code Playgroud)

你必须写:

extern void f( TwoValues const& );
//  ...

TwoValues tmp = { 1, 2 };
f( tmp );
Run Code Online (Sandbox Code Playgroud)

如果对象是动态分配的,那就更糟了,因为你必须首先分配,然后初始化,或者如上所述创建临时对象,然后编写new TwoValues( tmp )并使用隐式复制构造函数.

你必须选择.根据结构的用途,一个或另一个将是首选; 一方面,我有很多只在静态表中使用的结构,并且故意没有构造函数(并且只包含支持静态初始化的类型),并且使用它们来配置代码.另一方面,我也有许多结构体,它们是一个类的内部结构,沿着Node树或图形的线条; 这几乎总是有一个构造函数,以便于在运行中创建它们.如果不知道结构在应用程序中的作用,就没有"正确"的答案.


Fil*_*efp 13

声明一个空构造函数有副作用..

即使你的构造函数有一个空体,它仍然被认为是一个构造函数,因此某些对象属性将丢失 - 例如对象是POD.

有些情况下需要使用Plain Old Data -types,这可能会使您在没有特定原因的情况下完成您所做的事情.

在下一节中,阅读更多关于初始化而不使用defult构造函数的内容.


&&

您可以使用值初始化您的成员,而无需显式定义"不执行任何操作的构造函数",只需使用大括号中的大括号初始化语法,如下面的代码段所示.

struct Obj {
  int x, y;
};
Run Code Online (Sandbox Code Playgroud)

Obj a = {1,3}; /* a.x = 1, a.y = 2 */
Run Code Online (Sandbox Code Playgroud)

没有构造函数的缺点是= { ... }在编写C++ 03时在某些情况下无法初始化对象.

C++ 11为您解决了这个问题,请参阅下一节了解相关示例.


在C++ 11中,使用大括号(= { ... })的初始化已被赋予了增强的功能.

如下面的片段所示,Obj即使我们使用与本文前面相同的初始化形式,也会调用定义的构造函数.

struct DoubleBoth {
  DoubleBoth (int x, int y)
    : x(x*2), y(y*2) 
  {}  

  int x, y;
};
Run Code Online (Sandbox Code Playgroud)

在C++ 11之前,下面的代码段都是非法的:

DoubleBoth a = {1,2}; /* a.x = 2, a.y = 4 */
Run Code Online (Sandbox Code Playgroud)

struct Wrapper {
  Wrapper ()
    : value {3,4}
  {}

  DoubleBoth value;
};
Run Code Online (Sandbox Code Playgroud)

void func (DoubleBoth v = {1,2}) {  // c++11 only
  ...
}

func ({4,5}); // c++11 only, c++03 requires `DoubleBoth obj (0,1); func (obj);`
Run Code Online (Sandbox Code Playgroud)


CB *_*ley 7

您已经停止twoValues成为POD并且已经阻止结构的实例被默认或值初始化,这通常是期望的属性.就个人而言,如果你需要一个简单的C++ 03友好方法,我宁愿有一个免费的函数来制作临时实例.

例如

twoValues makeTwoValues(int x_, int y_)
{
    twoValues tmp = { x_, y_ };
    return tmp;
}

void f() {
    someFunction(makeTwoValues(1,2));
}
Run Code Online (Sandbox Code Playgroud)

例如,初始化类型的成员 twoValues

class X {
    twoValues tv;
public:
    X(int x, int y) : tv(makeTwoValues(x, y)) {}
};
Run Code Online (Sandbox Code Playgroud)

  • @Charles只是你必须写一个函数.这不是一个很大的缺点,但毕竟这通常是构造函数为您提供的,自由函数是一种丑陋的解决方法,您可以编写类似构造函数的东西以避免使用构造函数.从概念上讲,即使我理解保留POD可能是可取的,但这只是不确定. (2认同)

Yoc*_*mer 7

拥有这种构造函数要比使用列表初始化更安全.

使用列表初始化时:

twoValues anInstance = {1, 2};
Run Code Online (Sandbox Code Playgroud)

它实际上取决于结构中成员的顺序.在大多数情况下,这是完全随机的开始.

如果另一个程序员碰巧添加了另一个成员,或者按字母顺序对成员进行排序,它将无法正常工作.

拥有一个通过NAME将值分配给正确成员的构造函数更安全.