【问题标题】:Calling member functions from a constructor从构造函数调用成员函数
【发布时间】:2011-03-06 17:32:36
【问题描述】:

我知道这个问题的标题与此类似:C++: calling member functions within constructor?,但我问的是一个更笼统的问题。

从构造函数中调用成员函数是一种好习惯吗?它使阅读代码更容易,我更喜欢封装类型的方式(即每个代码块都有一个目标)。

一个说明性的例子,在 python 中:

class TestClass:
    def __init__(self):
        self.validate()

    def validate(self):
        # this validates some data stored in the class

这是否比在构造函数中编写validate 代码更好?这种方法有缺点吗?例如,函数开销是否更昂贵?

我个人更喜欢它的可读性,但这只是我的偏好。

干杯

【问题讨论】:

    标签: c++ oop


    【解决方案1】:

    我比 Python 更熟悉 C++,但我认为从构造函数调用成员函数没有问题,尤其是当这种做法能够从多个构造函数中分解出相似的代码时。在我的书中,任何减少冗余的东西都是好的。

    【讨论】:

      【解决方案2】:

      我不认为从构造函数调用成员函数有什么本质上的错误只要它们不是虚函数

      从构造函数调用虚成员函数的问题是子类可以覆盖该函数。这将导致构造函数在调用对象子类部分的构造函数之前调用子类中的重写实现。

      在 Java 中,privatestaticfinal 访问修饰符中的任何一个都可以通过阻止对超类方法的虚拟调用。我认为这些技术在 Python 中不可用。

      【讨论】:

      • 实际上,从构造函数调用虚方法非常有用。例如,获取特定类类型以在基构造函数中实例化的虚拟方法,其中特定类是已知基类的后代或已知接口的实现者。这样,您可以在基类中保留实例化和销毁,同时允许后代自定义组合。
      • 您是否建议将“在未初始化的对象上调用方法”作为跨语言通用用途的良好做法?我更喜欢使用 AbstractFactory 和/或 Builder 设计模式来解决您的示例问题。
      【解决方案3】:

      从可读性的角度来看,它肯定更好。不过,您可能需要在这里问自己一件事,是否允许在对象初始化后 运行 validate 方法。如果不是这种情况,您可以 a) 使用某种私有 initialized 变量或 b) 使用 Builder pattern 让您的对象在使用前进入有效状态。

      确保函数是私有的。您不想弄乱覆盖它的子类(除非这是设计所需要的,在这种情况下将其设为抽象/虚拟)。

      【讨论】:

        【解决方案4】:

        这样做的主要问题是成员函数必须使用可能仅部分初始化的对象。如果它(甚至意外地)在其他地方传递了对该对象的引用,其他代码也必须这样做。这会变得非常混乱且容易出错,尤其是当您开始在子类中覆盖这样的函数时。

        因此,一般而言,应避免或至少将这种做法限制在无法覆盖的函数中,并且它们绝不应将对正在构造的对象的引用传递给任何其他代码。

        【讨论】:

          【解决方案5】:

          您至少应该注意一个相关的“陷阱”:

          N3797 12.6.2/14

          可以为正在构建的对象调用成员函数(包括虚拟成员函数,10.3)。同样,正在构造的对象可以是 typeid 运算符 (5.2.8) 或 dynamic_cast (5.2.7) 的操作数。但是,如果这些操作在所有 mem-initializer s for base classes 已经完成,结果 操作的未定义。 [例子:

          class A {
          public:
             A(int);
          };
          
          class B : public A {
              int j;
          public:
              int f();
              B() : A(f()),  // undefined: calls member function
                             // but base A not yet initialized
              j(f()) { }     // well-defined: bases are all initialized
          };
          
          class C {
          public:
              C(int);
          };
          
          class D : public B, C {
              int i;
          public:
              D() : C(f()), // undefined: calls member function
                            // but base C not yet initialized
              i(f()) { }    // well-defined: bases are all initialized
          };
          

          ——结束示例]

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 2018-05-13
            • 2011-12-07
            • 1970-01-01
            • 2017-09-07
            • 2012-09-28
            • 2012-01-10
            • 1970-01-01
            • 1970-01-01
            相关资源
            最近更新 更多