如何在C ++构造函数中获得多态行为?

时间:2009-09-21 06:42:41

标签: c++ abstract virtual-functions

我有一个基类,我希望看起来像这样:

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

要强制派生类重写I并强制在构造每个对象时调用它。这习惯于做一些簿记,我需要知道正在构造什么类型的对象(但我将当前对象视为基类)。

这不起作用,因为C ++不允许你从构造函数中调用抽象虚函数。

有没有办法达到同样的效果?


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

  

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

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

(现在回到阅读该链接)

4 个答案:

答案 0 :(得分:7)

你不能从构造函数中调用虚方法(或者更确切地说,你可以调用它们,但是你最终会从当前构造的类中调用成员函数)。 ,问题是派生对象在那一刻还不存在。你可以做的很少,从构造函数中多态调用虚方法简直是不可能的。

您应该重新考虑您的设计 - 例如,将常量作为参数传递给构造函数。

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

有关详情,请参阅C++ faq。如果确实想要在构建期间调用虚拟函数,read this

答案 1 :(得分: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);
  }
}

在基础构造函数中调用虚方法通常是不受欢迎的,因为您永远无法确定特定方法的行为,并且(正如其他人已经指出的那样)派生构造函数将不会被调用。

答案 2 :(得分: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()
    {
    }
};

答案 3 :(得分:0)

您需要的是two-phase construction。使用Universal Programmer的治疗:添加另一层间接。