我知道这个问题的标题与此类似: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
代码更好吗?这种方法有缺点吗?例如,功能开销是否更昂贵?
我个人更喜欢它的可读性,但这只是我的偏好。
干杯
答案 0 :(得分:9)
我认为从构造函数调用成员函数时没有任何内在错误,前提是它们不是虚函数。
从构造函数调用虚拟成员函数的问题是子类可以覆盖该函数。这将导致构造函数在调用对象的子类部分的构造函数之前调用子类中的重写实现。
在Java中,任何一个私有,静态或最终访问修饰符都可以通过阻止从构造函数调用方法对超类方法的虚拟调用。我认为Python中没有这些技术。
答案 1 :(得分:4)
至少有一个相关的"陷阱"你应该知道:
N3797 12.6.2 / 14
可以为正在构建的对象调用成员函数(包括虚拟成员函数,10.3)。类似地,正在构造的对象可以是
typeid
运算符(5.2.8)或dynamic_cast
(5.2.7)的操作数。但是,如果在所有 mem-initializer之前,在 ctor-initializer (或直接或间接从 ctor-initializer 中调用的函数)中执行这些操作的基类完成了,结果 操作未定义。 [示例:的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 };
- 结束示例]
答案 2 :(得分:2)
这个问题的主要问题是成员函数必须处理可能只是部分初始化的对象。如果它(甚至意外地)将引用传递给其他地方的对象,则其他代码也必须相同。这可能会让人感到困惑和容易出错,特别是一旦你开始在子类中重写这样的函数。
因此,一般来说,应该避免这种做法,或者至少局限于无法覆盖的函数,并且它们不应该将对正在构造的对象的引用传递给任何其他代码。
答案 3 :(得分:1)
我比C ++更熟悉C ++,但我发现从构造函数调用成员函数没有问题,特别是当这种做法能够从多个构造函数中分解出类似的代码时。在我的书中,任何减少冗余的东西都是好的。
答案 4 :(得分:0)
从可读性的角度来看,它肯定更好。但是,您可能需要问自己的一件事是,是否允许验证方法在初始化对象之后运行。如果不是这种情况,您可以a)使用某种私有初始化变量或b)使用Builder pattern在使用它们之前使对象进入有效状态。
确保该功能是私密的。你不想搞乱覆盖它的子类(除非设计需要这个,在这种情况下使它成为抽象/虚拟)。