为什么 C++初始化列表在大括号之前?

发布于 2024-11-05 01:03:32 字数 396 浏览 1 评论 0原文

我想知道以下两堂课有什么区别。

例1:

class A
{
string name;
public:
  A(const char* _name):name(_name){}
  void print(){cout<<"A's name:"<<name<<endl;}
};

例2:

class A
{
string name;
public:
  A(const char* _name){name(_name);}
  void print(){cout<<"A's name:"<<name<<endl;}}

为什么例1通过了,最后一个错了? 谢谢

I want to know what's difference in the following two class.

example 1:

class A
{
string name;
public:
  A(const char* _name):name(_name){}
  void print(){cout<<"A's name:"<<name<<endl;}
};

example 2:

class A
{
string name;
public:
  A(const char* _name){name(_name);}
  void print(){cout<<"A's name:"<<name<<endl;}}

why the example 1 is passed and the last one is wrong?
Thanks

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(6

十秒萌定你 2024-11-12 01:03:32

在示例 1 中,您立即使用给定值初始化字符串。
在示例 2 中,您首先创建一个空字符串,然后再对其进行分配。

尽管存在一些性能差异,并忽略由于复制构造函数处理等原因可能存在的差异,但结果本质上是相同的。

但是,一旦您使用 const 成员,您就必须使用示例 1 的方式来执行此操作,例如,我通常按以下方式创建唯一 ID:

class SomeObject
{
    static unsigned int nextID = 0;
    const unsigned int ID;
    SomeObject() : ID(nextID++)
    {
        // you can't change ID here anymore due to it being const
    }
}

In example 1 you initialize the string with the given value right away.
In example 2 you create an empty string first and assign it later on.

Despite some performance differences and ignoring possible differences due to copy constructor handling etc. it's essentially the same result.

However once you use a const member you'll have to use example 1's way to do it, e.g. I usually create unique IDs the following way:

class SomeObject
{
    static unsigned int nextID = 0;
    const unsigned int ID;
    SomeObject() : ID(nextID++)
    {
        // you can't change ID here anymore due to it being const
    }
}
你不是我要的菜∠ 2024-11-12 01:03:32

第一个示例是实际初始化。它有很多优点,包括是设置 const 成员的唯一方法,并且具有适当的异常安全性。

AFAIK,第二个示例不是有效的 C++。如果您改为编写 name = name_,那么这只是正常的赋值。当然,这并不总是可能的。该对象可能是 const,或者没有定义赋值运算符。这种方法的效率也可能低于第一个示例,因为该对象既是默认初始化的,也是分配的。

至于为什么初始化列表位于构造函数主体之前;嗯,这就是语言的定义方式。

The first example is an actual initialization. It has a number of advantages, including being the only way to set up const members, and having proper exception-safety.

The second example is not valid C++, AFAIK. If you had instead written name = name_, then this would just be normal assignment. Of course, this isn't always possible; the object might be const, or not have an assignment operator defined. This approach could also be less efficient that the first example, because the object is both default-initialized and assigned.

As for why the initializer list is before the constructor body; well, that's just the way the language has been defined.

倦话 2024-11-12 01:03:32

这就是语言的定义方式。成员初始值设定项应放置在构造函数主体之前。

That's just how the language is defined. The member initializers should be placed before the body of the constructor.

青丝拂面 2024-11-12 01:03:32

在第一个示例中,成员名称是使用 ctr 获取 char * 作为参数来初始化的。

在第二种情况下,它首先使用默认的 ctr 进行初始化,然后通过赋值运算符 (operator=) 获取值。这就是为什么你的情况是错误的,它已经在那里构建了,所以你不能再次使用 ctr 你只能使用赋值运算符。

In the first example the member name is initialized with a ctr getting char * as parameter.

In the second case it is initialized with a default ctr at first and it gets value by the assignment operator (operator=) later. That's why it is wrong with your case that it is already constructed there so you can not use the ctr once again you could just use the assignment operator.

樱娆 2024-11-12 01:03:32

原因是名称查找在初始值设定项列表和函数体中的工作方式不同:

class A
{
  std::string foo; // member name
public:
  A(const char* foo) // argument name
    : foo(foo) // member foo, followed by argument foo.
  {
    std::cout << foo; // argument foo.
  }
};

如果初始值设定项列表位于函数体内,则成员 foo 和参数 foo 之间会存在歧义。

The reason is that name lookup works different in initializer lists and function bodies:

class A
{
  std::string foo; // member name
public:
  A(const char* foo) // argument name
    : foo(foo) // member foo, followed by argument foo.
  {
    std::cout << foo; // argument foo.
  }
};

If the initializer list was inside the function body, there would be an ambiguity between member foo and argument foo.

行至春深 2024-11-12 01:03:32

初始化列表背后的动机是由于 const 字段按值保存对象(而不是引用/指针字段)。

这些字段必须只初始化一次(由于它们的常量性)。如果 C++ 没有初始化列表,那么 ctor 看起来像这样:

class A {
public:
  const string s;
  const string t;

  A() {
    // Access to either s or t is not allowed - they weren't initialized
    s = "some-string";
    // now you can access s but you can't access t
    f(*this);

    t = "some other string";
    // From now you can access both ...
  }
}


void f(A& a) {
  // Can you access a.s or a.t?
  cout << a.s << a.t;
}

没有初始化列表,ctor 可以将 A 类型的部分初始化对象传递给函数,并且该函数将无法使用了解哪些字段尚未初始化。风险太大,编译器/链接器很难检查。

The motivation behind the initialization list is due to const field holding a object by value (as opposed to reference/pointer field).

Such fields must be initialized exactly once (due to their const-ness). If C++ didn't have initialization list then a ctor would look something like:

class A {
public:
  const string s;
  const string t;

  A() {
    // Access to either s or t is not allowed - they weren't initialized
    s = "some-string";
    // now you can access s but you can't access t
    f(*this);

    t = "some other string";
    // From now you can access both ...
  }
}


void f(A& a) {
  // Can you access a.s or a.t?
  cout << a.s << a.t;
}

Without an initialization list a ctor can pass a partially-initialized object of type A to a function, and that function will have no way of knowing which fields are initialized yet. Too risky and very difficult for the compiler/linker to check.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文