2009-09-21 48 views
4

我有,我想看看这样一个基类:如何获得C++构造函数中的多态行为?

class B 
{ 
    // should look like: int I() { return someConst; } 
    virtual int I() = 0; 
    public B() { something(I()); } 
} 

被强制派生类重写I并迫使其点的每个对象被创建时被调用。这被用来做一些簿记,我需要知道什么类型的对象正在构建(但我否则将当前对象作为基类)。

这不起作用,因为C++不会让你从构造函数中调用一个抽象的虚函数。

有没有办法获得相同的效果?


基于this link它似乎是答案是没有办法得到我想要的东西。然而它说的是:

简短的回答是:没有。基类不知道它是从哪个类派生出来的,这也是一件好事。 [...]也就是说,直到构造函数Derived1 :: Derived1开始,对象才会正式成为Derived1的实例。

但是在我的情况,我不想知道它,但它会成为。事实上,只要用户可以(事后)将其映射到一个班级,我甚至不关心我回来的东西。所以我甚至可以使用类似返回指针的东西并且避开它。

(现在回读该链接)

+0

阅读此:http://stackoverflow.com/questions/1425695/1426834。 您可以使用PIMPL。 – 2009-09-21 10:54:17

回答

6

不能调用虚方法从构造函数(或者更精确地说,你可以打电话他们,但你最终会调用成员函数从目前正在构建的类中),问题是派生对象在那个时刻还不存在。关于它几乎没有什么可做的,从构造函数多态调用虚拟方法根本就不成问题。例如,您应该重新考虑您的设计 - 将常量作为参数传递给构造函数。

class B 
{ 
public: 
    explicit B(int i) 
    { 
     something(i); 
    } 
}; 

查看C++ faq了解更多信息。如果你真的想在施工期间打电话虚拟功能,read this

+0

你的意思是“你不能......”? – Naveen 2009-09-21 06:53:19

+0

是的,这是一个错字,谢谢你Naveen :) – avakar 2009-09-21 06:54:34

+0

在构造函数是一个解决方法之后调用一个init()方法。但是,随后你需要在班级建造的任何地方进行改变 - 如果你使用的是工厂,这很好。 – 2009-09-21 06:59:35

0

也许在每个派生类型上使用静态工厂方法?这是在.NET中构造奇特对象的常用方法(请阅读:具有非常具体的初始化要求的对象),我已经开始意识到这一点。

class Base 
{ 
    protected Base(int i) 
    { 
    // do stuff with i 
    } 
} 

class Derived : public Base 
{ 
    private Derived(int i) 
    : Base(i) 
    { 
    } 

    public Derived Create() 
    { 
    return new Derived(someConstantForThisDerivedType); 
    } 
} 

在调用构造函数的基础虚拟方法一般是令人难以接受的,因为你永远是某些特定方法的行为,以及(如别人已经指出的那样)衍生构造将还未被调用。

0

这不会作为派生类的工作时,执行基类的构造并不存在:

class Base 
{ 
public: 
    Base() 
    { 
     // Will call Base::I and not Derived::I because 
     // Derived does not yet exist. 
     something(I()); 
    } 

    virtual ~Base() = 0 
    { 
    } 

    virtual int I() const = 0; 
}; 

class Derived : public Base 
{ 
public: 
    Derived() 
    : Base() 
    { 
    } 

    virtual ~Derived() 
    { 
    } 

    virtual int I() const 
    { 
     return 42; 
    } 
}; 

相反,你可以在参数添加到基类的构造函数:

class Base 
{ 
public: 
    explicit Base(int i) 
    { 
     something(i); 
    } 

    virtual ~Base() = 0 
    { 
    } 
}; 

class Derived : public Base 
{ 
public: 
    Derived() 
    : Base(42) 
    { 
    } 

    virtual ~Derived() 
    { 
    } 
}; 

或者如果你真的喜欢OOP,你还可以创建几个附加类:

class Base 
{ 
public: 
    class BaseConstructorArgs 
    { 
    public: 
     virtual ~BaseConstructorArgs() = 0 
     { 
     } 

     virtual int I() const = 0; 
    }; 

    explicit Base(const BaseConstructorArgs& args) 
    { 
     something(args.I()); 
    } 

    virtual ~Base() = 0 
    { 
    } 
}; 

class Derived : public Base 
{ 
public: 
    class DerivedConstructorArgs : public BaseConstructorArgs 
    { 
    public: 
     virtual ~DerivedConstructorArgs() 
     { 
     } 

     virtual int I() const 
     { 
      return 42; 
     } 
    }; 

    Derived() 
    : Base(DerivedConstructorArgs()) 
    { 
    } 

    virtual ~Derived() 
    { 
    } 
};