【问题标题】:Constructor and variable names in C++ vs. JavaC++ 与 Java 中的构造函数和变量名称
【发布时间】:2009-12-09 18:00:34
【问题描述】:

我正在学习来自 Java 背景的 C++(多年前了解一点 C)...

在 Java 中,通常的做法是在构造函数中使用“this”来区分作为参数传入构造函数的变量与在类中声明的变量:

class Blabla {

    private int a;
    private int b;

    Blabla(int a, int b){
        this.a = a;
        this.b = b;
    }
}

我喜欢这个,因为变量 Blabla.a 和作为参数传入构造函数的变量代表相同的东西,所以它们应该具有相同的名称感觉合乎逻辑......

在 C++ 中可以做到这一点吗?

【问题讨论】:

    标签: c++ constructor this


    【解决方案1】:

    是的,您可以使用this 来引用成员变量。也就是说,您经常会发现您的代码在惯用的 C++ 中如下所示:

    class Blabla {
      private:
        int a_;
        int b_;
    
      public:
        Blabla(int a, int b) : a_(a), b_(b) {}
    };
    

    如您所见,您通常不会将访问控制说明符(publicprotectedprivate)应用于每个成员,而是将它们分组。

    此外,如果您使用上面使用的初始化类型,则成员会被初始化两次 - 一次是在创建对象时使用默认构造函数(基本上是在执行大括号内的代码之前),第二次在分配给this->a的过程中。

    【讨论】:

    • 同意,但我希望优化编译器避免双重初始化。
    • 像 int 这样的基本类型不会被初始化两次,类类型会。如果您的构造函数没有初始化基本类型的成员变量,那么它在构造后将完全未初始化。
    【解决方案2】:

    是的,你使用this->a = a;

    另请注意,在 C++ 中,您应该在构造函数中使用初始化列表。

    class Blab 
    {
        public:
            Blab(int a, int b)
               :m_a(a),
                m_b(b)
            {
            }
    
        private:
            int m_a;
            int m_b;
    };
    

    编辑:

    您可以在初始化列表中使用:a(a), b(b),为您的数据成员 a 和传递给构造函数的参数 a 使用相同的名称。它们不必不同,但有些人认为对成员变量名称使用不同的命名约定是更好的做法。在上面的示例中,我使用了不同的名称来帮助阐明初始化列表实际上在做什么以及它是如何使用的。如果您愿意,可以使用this->a 设置另一个成员变量。例如如果成员变量和参数变量都是a和b,则

    class MyClass
    {
        public:
            MyClass(int a, int b);
        private:
            int a;
            int b;
    };
    
    // Some valid init lists for the MyClass Constructor would be
    :a(a), b(b)       // Init member a with param a and member b with parameter b
    :a(a), b(this->a) // Init member a with param a and init member b with member a (ignores param b)
    :a(5), b(25)      // Init member a with 5 and init member b with 25 (ignoring both params)
    

    应该提到,初始化列表应该按照它们在类定义中出现的顺序来初始化成员变量。一个好的编译器会在你不这样做时给你警告。

    【讨论】:

    • Erm... 你不能像在初始化列表中那样使用this->a。正在初始化的成员必须仅按名称指定:Blab(int a, int b) : a(a), b(b) {}
    • @史蒂夫。是的,当我编写代码时,我得到了“这个”的快乐。我已经更新了我的答案
    • 您不需要下划线:初始化器a(a) 表示“使用参数a 初始化成员a”。你是否被你的同事枪杀是另一回事。此外,您可以在表达式中使用this,例如Blab(int a) : a(a), b(this->a) {}
    • @史蒂夫。是的,我知道下划线是不必要的。我通常不使用它们,尽管在这种情况下我这样做是为了更清楚地了解正在做什么。
    • 所以,我可以使用 this->a 或稍微更改变量的名称,即添加尾随 '' 或前导 'm' ?
    【解决方案3】:

    由于在 C++ 中this 是一个指针,因此您可以使用this->var 访问它的成员变量。

    请注意,C++ 的约定往往与 Java 不同,通常使用 _var 表示私有变量,而不是通常的 Java 方式 this.var。当然,这取决于您要使用的约定。

    【讨论】:

    • 虽然我认为 m_* 的使用比 _* 更多。不过这真的没关系。
    • @Goz:MS 使用 m_*,所以习惯了他们的工具/框架的人经常这样做。相当多的其他人使用 *_ 代替。无论如何,this->* 是非常不寻常的,而 IME 几乎可以说是代码异味——大多数这样的代码似乎都比较差。
    • 其实使用_var之类的名字并不是一个好主意。前导下划线是为编译器和库实现者保留的(从技术上讲,该规则有更多细节,例如,两个前导下划线和一个大写字母、一个前导下划线等)
    • 前导“”由标准保留供编译器实现使用。不是此用途的有效选择。如果没有前导“m_”,我通常会看到使用尾随“”。
    • _var 可以,只要var 以小写字母开头。但是约定 _* 可能值得避免,这样想要“初始”大写字母的人就不要尝试_Var,这是保留的。
    【解决方案4】:

    只是总结一下,放在一个答案中。

    如果你想使用 this->a 方法,它看起来像这样

    class Blabla 
    {
        private:
            int a;
            int b;
    
        public:
            Blabla(int a, int b);
    }
    
    Blabla::Blabla(int a, int b)
    {
        this->a = a;
        this->b = b;
    }
    

    或者如果你使用 C++ 方式和 :a(a) 它看起来像这样

    class Blabla 
    {
        private:
            int a;
            int b;
    
        public:
            Blabla(int a, int b);
    }
    
    Blabla::Blabla(int a, int b):a(a), b(b)
    {
    }
    

    我个人认为 this->a 比将字母放在前面的匈牙利符号示例(如 m_a 或更多 c 样式的 _a)导致更易读的代码。

    【讨论】:

      猜你喜欢
      • 2013-06-04
      • 2012-10-04
      • 2016-03-05
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多