You're basically creating inversion of control within a constructor. The method in the base class that is being called gets called before the base class data is initialized (in most languages), which is dangerous, as well. It can easily lead to indeterminate behavior.
Remember, in most languages, when you construct a class, all of the base class construction runs first. So, if you have something like: MyClass() : MyBaseClass() {}, typically, MyBaseClass's constructor runs in its entirety, thenMyClass's constructor executes. However, by using a virtual method in the base class, you're calling an instance method in MyClass before it's fully initialized - which could be very dangerous.
This is a bad idea, because in most OOP languages, the child is initialized after the parent is initialized. If the abstract function is implemented in the child, then it may operate on data in the child under the incorrect assumption that it has already been initialized, which is not the case in parent construction.
Example:
class Base {
public:
Base() { virtualInit(); }
virtual ~Base() {}
protected:
virtual void virtualInit() {}
};
class Derived : public Base {
public:
Derived() : ptr_(new SomeObject) {}
virtual ~Derived() {}
protected:
virtual void virtualInit() {
// dereference ptr_
}
private:
scoped_ptr<SomeObject> ptr_;
};
In the example above, Base::Base() gets executed before Derived::Derived(), which is responsible for initializing ptr_. Hence, when virtualInit() is called from Base::Base() it dereferences an uninitialized pointer, leading to all sorts of trouble. This is why ctors and dtors should call only non-virtual functions (in C++), final functions (in Java), or the language-specific equivalent.
I can't see the reasoning of why you would want to do this, let alone qualify it. Sounds like your trying to inject some functionality into the object. Why wouldn't you just overload the constructor or create a property that can be set so that you can inject the functionality through composition or even create the constructor with a parameter which is the IOC object.
As another has already posted, it does depend on the context in which your trying to solve a particular problem. The natural fit would be to adhere to an interface, develop an abstract class, and overload the constructor in each implementation. Without further information I can only comment on what has been posted in your question.
This design you have can not be regarded good or bad. Simply from the fact that it may be the only way you can achieve what your trying to do.
It is only then a GOOD idea, IFF you can manage it to not shoot in your own foot. But anyway, OOP is always prone to bad designs; so if your language allows other paradigms than OOP, to use OOP in this case is definitely a BAD choice.
At least in C++, the child class defines in which sequence all the initialisations are made; that are the initialisations of all member-variables and the constructors of all parent classes. This has to be considered!
Alternatively, you could give the constructor (as parameter) a pointer to a specific function (I would prefer static functions), instead of calling an abstract member-function. This could be a far more elegant and sane solution; and this is the usual solution in (probably all) non-OOP languages. (in java: A pointer to one function or a list of functions is the design pattern of an interface and vice versa.)
发布评论
评论(4)
这是一个坏主意。
您基本上是在构造函数中创建控制反转。基类中被调用的方法在基类数据初始化之前被调用(在大多数语言中),这也很危险。它很容易导致不确定的行为。
请记住,在大多数语言中,当您构造一个类时,所有基类构造都会首先运行。因此,如果您有类似以下内容:
MyClass() : MyBaseClass() {}
,通常,MyBaseClass
的构造函数会完整运行,然后MyClass
的构造函数执行。但是,通过在基类中使用虚拟方法,您将在完全初始化之前调用 MyClass 中的实例方法 - 这可能非常危险。This is a bad idea.
You're basically creating inversion of control within a constructor. The method in the base class that is being called gets called before the base class data is initialized (in most languages), which is dangerous, as well. It can easily lead to indeterminate behavior.
Remember, in most languages, when you construct a class, all of the base class construction runs first. So, if you have something like:
MyClass() : MyBaseClass() {}
, typically,MyBaseClass
's constructor runs in its entirety, thenMyClass
's constructor executes. However, by using a virtual method in the base class, you're calling an instance method inMyClass
before it's fully initialized - which could be very dangerous.这是一个坏主意,因为在大多数 OOP 语言中,子级是在父级初始化之后初始化的。如果抽象函数在子进程中实现,那么它可能会在错误的假设下对子进程中的数据进行操作,即它已经被初始化,而在父进程构造中则不是这种情况。
示例:
在上面的示例中,
Base::Base()
在Derived::Derived()
之前执行,后者负责初始化ptr_
。因此,当从 Base::Base() 调用 virtualInit() 时,它会取消引用未初始化的指针,从而导致各种麻烦。这就是为什么 ctor 和 dtor 应该只调用非虚函数(在 C++ 中)、final 函数(在 Java 中)或特定于语言的等效函数。This is a bad idea, because in most OOP languages, the child is initialized after the parent is initialized. If the abstract function is implemented in the child, then it may operate on data in the child under the incorrect assumption that it has already been initialized, which is not the case in parent construction.
Example:
In the example above,
Base::Base()
gets executed beforeDerived::Derived()
, which is responsible for initializingptr_
. Hence, whenvirtualInit()
is called fromBase::Base()
it dereferences an uninitialized pointer, leading to all sorts of trouble. This is why ctors and dtors should call only non-virtual functions (in C++), final functions (in Java), or the language-specific equivalent.我看不出你为什么要这样做的原因,更不用说限定它了。听起来像是您试图向对象注入一些功能。为什么不重载构造函数或创建一个可以设置的属性,以便可以通过组合注入功能,甚至使用 IOC 对象作为参数创建构造函数。
正如另一个人已经发布的那样,它确实取决于您尝试解决特定问题的上下文。自然的选择是遵守接口、开发抽象类并在每个实现中重载构造函数。如果没有进一步的信息,我只能对您问题中发布的内容发表评论。
你的这个设计不能说是好是坏。简单来说,这可能是您实现目标的唯一方法。
I can't see the reasoning of why you would want to do this, let alone qualify it. Sounds like your trying to inject some functionality into the object. Why wouldn't you just overload the constructor or create a property that can be set so that you can inject the functionality through composition or even create the constructor with a parameter which is the IOC object.
As another has already posted, it does depend on the context in which your trying to solve a particular problem. The natural fit would be to adhere to an interface, develop an abstract class, and overload the constructor in each implementation. Without further information I can only comment on what has been posted in your question.
This design you have can not be regarded good or bad. Simply from the fact that it may be the only way you can achieve what your trying to do.
只有这样,这才是一个好主意,如果你能做到这一点,就不会搬起石头砸自己的脚。但无论如何,OOP 总是容易出现糟糕的设计;因此,如果您的语言允许 OOP 之外的其他范例,那么在这种情况下使用 OOP 绝对是一个糟糕的选择。
至少在 C++ 中,
子类定义所有初始化的顺序;这是所有成员变量和所有父类的构造函数的初始化。这个必须要考虑!
或者,您可以为构造函数(作为参数)提供指向特定函数的指针(我更喜欢静态函数),而不是调用抽象成员函数。这可能是一个更加优雅和理智的解决方案;这是(可能是所有)非 OOP 语言中的常见解决方案。 (在java中:指向一个函数或函数列表的指针是接口的设计模式,反之亦然。)
It is only then a GOOD idea, IFF you can manage it to not shoot in your own foot. But anyway, OOP is always prone to bad designs; so if your language allows other paradigms than OOP, to use OOP in this case is definitely a BAD choice.
At least in C++,
the child class defines in which sequence all the initialisations are made; that are the initialisations of all member-variables and the constructors of all parent classes. This has to be considered!
Alternatively, you could give the constructor (as parameter) a pointer to a specific function (I would prefer static functions), instead of calling an abstract member-function. This could be a far more elegant and sane solution; and this is the usual solution in (probably all) non-OOP languages. (in java: A pointer to one function or a list of functions is the design pattern of an interface and vice versa.)