假设有一个带有构造函数的抽象类,该构造函数调用一个尚未由子类实现的受保护抽象方法。这是一个好主意还是坏主意?为什么呢?
答案 0 :(得分:3)
这是一个坏主意。
您基本上是在构造函数中创建控件反转。正在调用的基类中的方法在初始化基类数据之前(在大多数语言中)被调用,这也是危险的。它很容易导致不确定的行为。
请记住,在大多数语言中,构造类时,所有基类构造都先运行。因此,如果您有类似MyClass() : MyBaseClass() {}
的内容,通常MyBaseClass
的构造函数完整运行,则然后 MyClass
的构造函数执行。但是,通过在基类中使用虚方法,您在MyClass
中调用实例方法,然后才能完全初始化 - 这可能非常危险。
答案 1 :(得分:2)
这是个坏主意,因为在大多数OOP语言中,在初始化父级之后初始化子级。如果抽象函数是在子函数中实现的,那么它可能会在不正确的假设已经初始化的情况下对子元素中的数据进行操作,而在父构造中则不然。
示例:
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_;
};
在上面的示例中,Base::Base()
在Derived::Derived()
之前执行,ptr_
负责初始化virtualInit()
。因此,当从Base::Base()
调用{{1}}时,它会取消引用未初始化的指针,从而导致各种麻烦。这就是为什么ctors和dtors应该只调用非虚函数(在C ++中),最终函数(在Java中)或特定于语言的等价函数。
答案 2 :(得分:1)
我看不出你为什么要这样做的原因,更不用说是否有资格了。听起来像是在尝试向对象中注入一些功能。为什么不重载构造函数或创建可以设置的属性,以便可以通过组合注入功能,甚至可以使用IOC对象的参数创建构造函数。
正如另一个已发布的那样,它确实取决于您尝试解决特定问题的上下文。自然适合是遵循接口,开发抽象类,并在每个实现中重载构造函数。如果没有进一步的信息,我只能评论您的问题中发布的内容。
这种设计你不能算是好还是坏。简单地说,它可能是您实现目标的唯一方式。
答案 3 :(得分:0)
这只是一个好主意,IFF你可以管理它不能自己动手。但无论如何,OOP总是容易出现糟糕的设计;因此,如果您的语言允许其他范例而不是OOP,那么在这种情况下使用OOP绝对是一个不错的选择。
至少在C ++中, 子类定义所有初始化的顺序;这是所有成员变量的初始化和所有父类的构造函数。这必须考虑!
或者,你可以给构造函数(作为参数)一个指向特定函数的指针(我更喜欢静态函数),而不是调用抽象成员函数。这可能是一个更加优雅和理智的解决方案;这是(可能所有)非OOP语言的常用解决方案。 (在java中:指向一个函数或函数列表的指针是接口的设计模式,反之亦然。)