7

我有一个我想看起来像这样的基类:

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

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

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

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


基于这个链接,答案似乎是没有办法得到我想要的。然而它说的是:

最简洁的答案是不。基类对派生自哪个类一无所知——这也是一件好事。[...]也就是说,在构造函数 Derived1::Derived1 开始之前,该对象不会正式成为 Derived1 的实例。

但是在我的情况下,我不想知道它什么,而是它会变成什么。事实上,只要用户可以(事后)将它映射到一个类,我什至不在乎我得到了什么。所以我什至可以使用返回指针之类的东西并摆脱它。

(现在回到阅读该链接)

4

4 回答 4

8

您不能从构造函数调用虚方法(或者更准确地说,您可以调用它们,但最终会从当前正在构造的类中调用成员函数)。问题是派生对象没有仍然存在于那一刻。您对此几乎无能为力,从构造函数中多态地调用虚方法是不可能的。

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

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

有关更多信息,请参阅C++ 常见问题解答。如果你真的想在构造过程中调用虚函数,请阅读这篇文章

于 2009-09-21T06:48:29.690 回答
1

也许在每个派生类型上使用静态工厂方法?这是在 .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);
  }
}

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

于 2009-09-21T06:58:04.510 回答
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()
    {
    }
};
于 2009-09-21T07:11:03.110 回答
0

你需要的是两期建设。使用通用程序员的解决方法:添加另一层间接。

于 2009-09-21T08:34:37.167 回答