【问题标题】:c++ Using class member as a parameter in constructorc++ 在构造函数中使用类成员作为参数
【发布时间】:2023-03-18 20:55:02
【问题描述】:

我有一个类,我需要使用其中一个成员作为构造函数参数来初始化同一类的另一个 const 成员。

class A
{
private:
   M1Type m1;
   const M2Type m2;
public:
   A(x) : m1(x), m2(m1){}
};

这是初始化 m2 的正确方法吗?列表初始化中m1的构造完成了吗?

更新: 抱歉,我错过了 x 的类型(更像是伪代码)。假设任何原始类型。

【问题讨论】:

    标签: c++ oop constructor


    【解决方案1】:

    是的,“m1 的构造完成”当它用于初始化 m2 并且如果可以从 M1Type 构造 M2Type,这很好 - 但 x 需要A(x) 中的一个类型。

    初始化的顺序是你在类中定义成员变量的顺序,而不是你在成员初始化器列表中使用它们的顺序:

    M1Type m1;
    const M2Type m2;
    
    A(M1Type x) : m2(m1), m1(x) {} // wrong order, but still ok
    

    如果x 的类型可用于构造M1TypeM2Type 并获得与使用M1Type 构造x 构造M2Type 相同的结果,则您如果您稍后重新组织成员变量,不妨使用x 来构造两者,以免出现问题。但这并不总是可能的。

    例子:

    struct M1Type {
        explicit M1Type(double) {};
    };
    
    struct M2Type {
        explicit M2Type(M1Type) {}
    };
    
    class A {
    public:
       M1Type m1;
       const M2Type m2;
    public:
       // error: no matching function for call to 'M2Type::M2Type(double&)':
       // A(double x) : m1(x), m2(x) {}
    
       A(double x) : m1(x), m2(m1) {}   // OK
    };
    

    【讨论】:

      【解决方案2】:

      成员按照它们在类定义中出现的顺序进行初始化(与初始化列表中的顺序无关)。因此,首先初始化m1,您可以使用它的值来初始化m2

      这段代码

      class A
      {
      private:
         M1Type m1;
         const M2Type m2;
      public:
         A(int x) : m1(x), m2(m1){}
      };
      

      很好(除了缺少x 的类型)。不过,如果可能的话,我宁愿这样写:

      class A
      {
      private:
         M1Type m1;
         const M2Type m2;
      public:
         A(int x) : m1(x), m2(x){}
      };
      

      因为现在正确性不取决于成员的顺序。重构时可能会发生变化。当初始化列表中的顺序不同时,编译器通常会发出警告,但您可以依赖正确的代码,而不是依赖警告,而不管成员的顺序如何。


      请注意,编译器不一定会警告此代码(交换成员的顺序):

      class A
      {
      private:
         const M2Type m2;
         M1Type m1;
      
      public:
         A(int x) : m2(m1),m1(x) {}  // !! most likely UB !!
      };
      

      但如果M2Types 构造函数使用m1 的值,它具有未定义的行为,因为m1 未初始化使用。因此,当成员的初始化相互依赖时应该小心。

      【讨论】:

        【解决方案3】:

        假设 M2Type 的构造函数接受 M1Type 参数应该可以工作。

        PS: A(x) - 应该指定 x 的类型。

        执行下面的代码可以确保它正常工作:

        #include <iostream>
        class M1Type
        {
        public:
            int iField;
            M1Type(int x): iField{x}
            {
                std::cout << "M1Type(int x)" << iField << std::endl;
            }
        };
        class M2Type
        {
        public:
            int iField;
            M2Type(M1Type m1) : iField{ m1.iField + 500 }
            {
                std::cout << "M2Type(M1Type m1)" << iField << std::endl;
            }
        };
        class A
        {
        private:
            M1Type m1;
            const M2Type m2;
        public:
            A(int x) : m1(x), m2(m1) 
            {
                std::cout << "A(int x): M1Type: " << m1.iField << "; M2Type: " << m2.iField << std::endl;
            }
        };
        int main()
        {
            A objA(73);
        }
        

        控制台输出为:

        M1Type(int x)73
        M2Type(M1Type m1)573
        A(int x): M1Type: 73; M2Type: 573
        

        【讨论】:

          猜你喜欢
          • 2016-07-28
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2011-12-07
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多