可以使用大括号初始化列表语法来初始化私有成员吗?

huangapple go评论74阅读模式
英文:

Is it possible to use the brace initialiser list syntax for private members?

问题

以下是您要翻译的内容:

以下代码可编译:

#include <vector>
struct Foo
{
    int a;
    int b;
};

int main()
{
    std::vector<Foo> foos;
    foos.emplace_back(Foo{1, 2});
}

然而,如果我将 struct 替换为 class,它会失败。除了这个更改(我想保持成员私有),是否有什么我可以做的,以便我可以使用 Foo{1, 2} 的表示法?我很想避免自己编写一个 Foo 构造函数。

我正在使用 C++17,当然也对一般性的 C++ 答案感兴趣。

注释:

  1. 编译错误(MSVC)如下:
c:\...: error C2440: 'initializing': 无法从 'initializer list' 转换为 'Foo'
c:\...: note: 源类型无法接受,或构造函数重载解析模糊
c:\...: error C2672: 'std::vector<Foo,std::allocator<_Ty>>::emplace_back': 找不到匹配的重载函数
        with
        [
            _Ty=Foo
        ]
英文:

The following code compiles

#include &lt;vector&gt;
struct Foo
{
    int a;
    int b;
};

int main()
{
    std::vector&lt;Foo&gt; foos;
    foos.emplace_back(Foo{1, 2});
}

However, it fails if I replace struct with class<sup>1</sup>. Aside from doing that (I would like to keep the members private), is there something I can do to enable me to use the Foo{1, 2} notation? I'm keen to avoid writing a constructor for Foo myself.

I'm using C++17 although of course will be interested in general C++ answers.

<hr>

<sup>1</sup> Compile error (MSVC) is

1&gt;c:\...: error C2440: &#39;initializing&#39;: cannot convert from &#39;initializer list&#39; to &#39;Foo&#39;
1&gt;c:\...: note: No constructor could take the source type, or constructor overload resolution was ambiguous
1&gt;c:\...: error C2672: &#39;std::vector&lt;Foo,std::allocator&lt;_Ty&gt;&gt;::emplace_back&#39;: no matching overloaded function found
1&gt;        with
1&gt;        [
1&gt;            _Ty=Foo
1&gt;        ]

答案1

得分: 2

你正在使用的功能称为聚合初始化。根据C++17标准中对聚合的定义[dcl.init.aggr/1.2]

> 聚合是一个数组或一个满足以下条件的类
(1.1) 没有用户提供的、显式的或继承的构造函数
(1.2) 没有私有或受保护的非静态数据成员
...

因此,要实现你的要求,没有实现构造函数是不可能的。背后的原因很简单 - 如果类/结构体定义了某些成员为私有,就不应该以任何方式从外部访问它们。否则,这就违反了封装的概念。

请注意,花括号本身不一定表示聚合初始化。例如,Foo{a, b} 是调用构造函数的有效语法:

class Foo
{
    int a;
    int b;

public:
    Foo(int a_, int b_) : a{a_}, b{b_} {}
};

Foo f{1, 2}; // 在这里调用构造函数
英文:

The feature you are using here is called aggregate initialization. By definition of aggregate from the C++17 standard [dcl.init.aggr/1.2]:

> An aggregate is an array or a class with
(1.1) no user-provided, explicit, or inherited constructors
(1.2) no private or protected non-static data members
...

Thus, it's just impossible to do what you are asking for without implementing a constructor. The reasoning behind this is simple - if class/struct defines something to be private, it shouldn't be accessible from outside in any way. Otherwise, it contradicts the concept of encapsulation.

Please note that the curly braces themselves don't necessarily mean aggregate initialization. Foo{a, b} is a valid syntax for calling a constructor, for example:

class Foo
{
    int a;
    int b;

public:
    Foo(int a_, int b_) : a{a_}, b{b_} {}
};

Foo f{1, 2}; // Calls constructor here

答案2

得分: 1

private 意味着它是私有的。这是一个实现细节。用户不必关心它。您可以更改或删除私有成员,类的用户不会注意到,只要不触及公共接口,他们的代码将继续编译而不会出错。

编写一个构造函数:

struct Foo
{
    Foo(int a, int b) : a(a), b(b) {}
    private:
    int a;
    int b;
};

为了说明我的观点,考虑以后您将类更改为:

struct Foo
{
    Foo(int a, int b) : ab(a + b) {}
    private:
    int ab;
};

不同范围的输入导致溢出和不同的 sizeof,用户不会注意到差异。这是好的,因为只有私有部分被修改。

英文:

private means its private. Its an implementation detail. A user does not have to care about it. You can change or remove private members and a user of the class will not notice, their code will continue to compile without errors as long as the public interface is not touched.

Write a constructor:

struct Foo
{
    Foo(int a,int b) : a(a),b(b) {}
    private:
    int a;
    int b;
};

To illustrate my point, consider later you change the class to

struct Foo
{
    Foo(int a,int b) : ab(a+b) {}
    private:
    int ab;
};

Different ranges of input leading to overflow and different sizeof aside, a user will not notice the difference. And thats good, because only the private part was modified.

huangapple
  • 本文由 发表于 2023年5月25日 00:30:15
  • 转载请务必保留本文链接:https://go.coder-hub.com/76325672.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定