代码之家  ›  专栏  ›  技术社区  ›  BCS

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

  •  5
  • BCS  · 技术社区  · 15 年前

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

    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 回复  |  直到 15 年前
        1
  •  8
  •   avakar    15 年前

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

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

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

    C++ faq 更多。如果你 真正地 read this

        2
  •  0
  •   Tullo_x86    15 年前

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

        3
  •  0
  •   dalle    15 年前

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

    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()
        {
        }
    };
    
        4
  •  0
  •   Community CDub    8 年前

    你需要的是 two-phase construction