8

这可能是一个愚蠢的问题,但我还是有点好奇……最近我在做我以前同事的一个项目,我注意到他真的很喜欢用这样的东西:

int foo(7);

代替:

int foo = 7;

这是用 C++ 语言做的正常/好方法吗?它有什么好处吗?(或者这只是他喜欢的一些愚蠢的编程风格......?

这真的让我想起了如何在类构造函数中分配类成员变量的一个好方法......像这样:

class MyClass
{
public:
   MyClass(int foo) : mFoo(foo)
   { }

private:
   int   mFoo;
};

而不是这个:

class MyClass
{
public:
   MyClass(int foo)
   {
      mFoo = foo; 
   }

private:
   int   mFoo;
};
4

8 回答 8

10

对于基本类型,没有区别。使用与现有代码一致并且看起来更自然的任何一个。

否则,

A a(x);

执行直接初始化,并且

A a = x;

执行复制初始化

第二部分是成员初始化列表,在 StackOverflow 上有很多关于它的问答。

于 2012-09-05T15:46:04.093 回答
4

两者都是有效的。对于内置类型,它们做同样的事情;对于类类型,存在细微差别。

MyClass m(7);  // uses MyClass(int)
MyClass n = 3; // uses MyClass(int) to create a temporary object,
               // then uses MyClass(const MyClass&) to copy the
               // temporary object into n

明显的含义是,如果MyClass没有复制构造函数,或者它有一个但不可访问,则尝试构造失败。如果构造成功,则允许编译器跳过复制构造函数并MyClass(int)直接使用。

于 2012-09-05T15:47:50.660 回答
3

以上所有答案都是正确的。只需添加 C++11 支持另一种方式,即他们所说的用于初始化变量的通用方式。

int a = {2} ;

或者

int a {2} ;
于 2012-09-05T15:49:56.243 回答
2

我更喜欢使用括号样式......虽然我总是使用空格来区分函数或方法调用,我不使用空格:

int foo (7); // initialization
myVector.push_back(7); // method call

我更喜欢全面使用它进行初始化的原因之一是因为它有助于提醒人们这不是一项任务。因此,赋值运算符的重载将不适用:

#include <iostream>

class Bar {
private:
    int value;
public:
    Bar (int value) : value (value) {
        std::cout << "code path A" << "\n";
    }
    Bar& operator=(int right) {
        value = right;
        std::cout << "code path B" << "\n";
        return *this;
    }
};

int main() {
    Bar b = 7;
    b = 7;
    return 0;
}

输出是:

code path A
code path B

感觉就像等号的存在掩盖了差异。即使它是“常识”,我也喜欢让初始化看起来与赋值明显不同,因为我们能够这样做。

于 2012-09-05T16:12:57.040 回答
2

你的问题根本不是一个愚蠢的问题,因为事情并不像看起来那么简单。假设你有:

class A {
  public:
    A() {}
};

class B {
  public:
    class B(A const &) {}
};

写作

B b = B(A());

要求 B 的复制构造函数是可访问的。写作

B b = A();

还要求 B 的转换构造函数 B(A const &) 未显式声明。另一方面,如果你写

A a;
B b(a);

一切都很好,但如果你写

B b(A());

这被编译器解释为一个函数 b 的声明,它接受一个无名参数,该参数是一个返回 A 的无参数函数,导致神秘的错误。这被称为C++ 中最令人头疼的 parse

于 2012-09-05T16:08:52.237 回答
2

这是初始化变量的 C++ 风格 - C++ 为基本类型添加了它,因此可以将相同的形式用于基本类型和用户定义类型。这对于旨在为任何一种类型实例化的模板代码来说可能非常重要。

您是否喜欢将其用于基本类型的正常初始化是一种风格偏好。

请注意,C++11 还添加了统一初始化语法,它允许对所有类型使用相同的初始化样式 - 甚至像 POD 结构和数组这样的聚合(尽管用户定义的类型可能需要有一个新类型的构造函数,该构造函数需要一个初始化列表以允许与它们一起使用统一的语法)。

于 2012-09-05T15:46:33.080 回答
2

其他几个好的答案指出了构造“就地”(ClassType v(<constructor args>))和创建临时对象并使用复制构造函数复制它(ClassType v = <constructor arg>)之间的区别。我认为还需要补充两点。首先,第二种形式显然只有一个参数,所以如果你的构造函数接受多个参数,你应该更喜欢第一种形式(是的,有一些方法可以解决这个问题,但我认为直接构造更简洁易读 - 但是,正如已经指出的那样,这是个人喜好)。

其次,如果您的复制构造函数所做的事情与您的标准构造函数有很大不同,那么您使用的形式很重要。大多数时候情况并非如此,有些人会争辩说这样做是个坏主意,但语言确实允许这种情况(尽管如此,你最终会遇到所有的惊喜,是你自己的错)。

于 2012-09-05T15:54:09.483 回答
1

这只是初始化某些东西的语法:-

SomeClass data(12, 134);

这看起来很合理,但是

int data(123);

看起来很奇怪,但它们的语法相同。

于 2012-09-05T15:43:29.160 回答