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

发布于 2024-08-05 05:30:08 字数 736 浏览 8 评论 0原文

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

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

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

这是行不通的,因为 C++ 不允许您从构造函数调用抽象虚函数。

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


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

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

但就我而言,我不想知道它是什么,而是想知道它会变成什么。事实上,我什至不关心我得到什么,只要用户可以(事后)将其映射到一个类。所以我什至可以使用像返回指针这样的东西并摆脱它。

(现在回到阅读该链接)

I have a base class that I want to look like this:

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

The point being to force deriving classes to override I and force it to be called when each object is constructed. This gets used to do some bookkeeping and I need to know what type of object is being constructed (but I otherwise treat the current object as the base class).

This doesn't work because C++ won't let you call an abstract virtual function from the constructor.

Is there a way to get the same effect?


Based on this link it would seem that the answer is there is no way to get what I want. However what it says is:

The short answer is: no. A base class doesn't know anything about what class it's derived from—and it's a good thing, too. [...] That is, the object doesn't officially become an instance of Derived1 until the constructor Derived1::Derived1 begins.

However in my case I don't want to know what it is but what it will become. In fact, I don't even care what I get back as long as I the user can (after the fact) map it to a class. So I could even use something like a return pointer and get away with it.

(now back to reading that link)

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

穿越时光隧道 2024-08-12 05:30:08

您不能从构造函数中调用虚方法(或者更准确地说,您可以调用它们,但最终会从当前正在构造的类中调用成员函数)。是派生对象此时还不存在。您对此无能为力,从构造函数多态调用虚拟方法根本不可能。

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

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

有关详细信息,请参阅 C++ 常见问题解答。如果您确实想在构造过程中调用虚函数,阅读此内容

You can't call virtual methods from the constructor (or to be more precise, you can call them, but you'll end up calling the member function from the class currently being constructed)., the problem is that the derived object does not yet exist at that moment. There is very little you can do about it, calling virtual methods from the constructor polymorphically is simply out of the question.

You should rethink your design -- passing the constant as an argument to the constructor, for example.

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

See C++ faq for more. If you really want to call virtual functions during construction, read this.

南风起 2024-08-12 05:30:08

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

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

Perhaps use a static factory method on each derived type? This is the usual way to construct exotic objects (read: those with very specific initialisation requirements) in .NET, which I have come to appreciate.

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);
  }
}

Calling virtual methods in base constructors is generally frowned upon, as you can never be certain of a particular method's behaviour, and (as somebody else already pointed out) derived constructors will not have yet been called.

烂柯人 2024-08-12 05:30:08

这将不起作用,因为执行基类构造函数时派生类还不存在:

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()
    {
    }
};

That will not work as the derived class does not yet exist when the base class constructor is executed:

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;
    }
};

Instead you could add the arguments to the base class constructor:

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

    virtual ~Base() = 0
    {
    }
};

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

    virtual ~Derived()
    {
    }
};

Or if you're really fond of OOP you could also create a couple of additional classes:

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()
    {
    }
};
﹉夏雨初晴づ 2024-08-12 05:30:08

您需要的是两阶段构建。使用通用程序员的治疗方法:添加另一层间接层。

What you need is two-phase construction. Use the Universal Programmer's cure: Add another layer of indirection.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文