【问题标题】:c++ variable assignment, is this a normal way..?c ++变量赋值,这是一种正常的方式..?
【发布时间】:2012-08-30 09:18:41
【问题描述】:

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

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;
};

【问题讨论】:

    标签: c++ variables styles variable-assignment


    【解决方案1】:

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

    int a = {2} ;
    

    int a {2} ;
    

    【讨论】:

    • 这与其他方式有何不同?
    • {} 用于从一系列值中赋值,而不是调用特定的构造函数。具体来说:vector<int> a = {1, 2},构造一个包含两个元素的向量,而 vector<int> a(1, 2) 构造一个包含一个元素的向量。
    • {} 统一初始化语法可以在没有= 的情况下使用。 (= 它确实复制初始化。)@MooingDuck 此外,它不必使用 initializer_list 构造函数,如果有匹配的构造函数,它恰好更喜欢 initializer_list 构造函数。 struct S { S(char const *c, int i) {} }; S s{"hey", 2};
    • @bames53:忘了它不需要=。你是对的,它可以使用其他构造函数,但它不应该用于其他构造函数,除了那些类似于 initializer_list 构造函数的构造函数。 EG,默认构造函数和转换构造函数。
    • @MooingDuck 我不同意除了类似列表的构造函数之外不应使用它。这对于避免最麻烦的解析很有好处。此外,IMO 在新代码中使用统一的初始化语法是合理的,除非在极少数情况下必须使用 () 语法。
    【解决方案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
    

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

    【讨论】:

      【解决方案3】:

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

      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++'s most vexing parse

      【讨论】:

        【解决方案4】:

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

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

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

        【讨论】:

        • 但请记住,统一初始化语法不是完全替代旧的() 构造函数调用。应使用统一初始化从一系列一个或多个值进行初始化,() 用于任何其他构造函数。
        • @MooingDuck:在我看来,关于是否应该统一使用统一初始化的推荐做法,事情仍在不断变化。
        • 如果您的意思是像 always 中的“应该统一使用”,那么这显然不是,因为{} 语法不能调用所有构造函数。否则,是的,辩论似乎比我想象的要多。
        【解决方案5】:

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

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

        【讨论】:

          【解决方案6】:

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

          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)

          【讨论】:

          • 如果 MyClass c-tor 是显式的,它也会失败。
          【解决方案7】:

          对于基本类型没有区别。使用与现有代码一致且对您来说更自然的代码。

          否则,

          A a(x);
          

          执行直接初始化,并且

          A a = x;
          

          执行复制初始化

          第二部分是成员初始化列表,StackOverflow 上有很多关于它的 Q&A。

          【讨论】:

            【解决方案8】:

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

            SomeClass data(12, 134);
            

            这看起来很合理,但是

            int data(123);
            

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

            【讨论】:

            • 你可能觉得它看起来很奇怪,但对我来说一点也不奇怪:P
            • 好吧,如果你不习惯的话看起来很奇怪。我现在越来越多地编写这样的代码以保持一致性。
            • 我猜是口味问题。我使用等号初始化整数、双精度等。即使是孩子也能理解int a = 5 的含义。
            • 说实话,我的实践表明,有时像int foo(7); 这样的风格真的很令人困惑......!想象一下,如果你有这样的东西 typedef int Foos; 并且在某些人的代码深处你会写出这样的东西 Foos someFoo(7); .. 通常我会认为“Foos”是某种类,并且我正在分配值“7 " 通过 "Foos" 构造函数...
            猜你喜欢
            • 1970-01-01
            • 2016-09-06
            • 1970-01-01
            • 2015-02-19
            • 1970-01-01
            • 2020-12-18
            • 2017-06-16
            • 2020-06-26
            • 2020-07-31
            相关资源
            最近更新 更多