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

是否有方法阻止派生类进一步实现虚拟函数?

  •  1
  • Dirt  · 技术社区  · 10 年前

    似乎在C++中(或者它是一般的OOP概念吗?) 一次虚拟始终虚拟 事情是这样的。我想知道是否还有什么可以阻止的。我有这种情况,需要我所问的。

    假设我有这样的工厂课程

    class Object;
    class GeneralFactory
    {
    private:
        virtual Object* CreateObject() = 0;
    };
    

    现在我有一个专门的工厂,它仍然允许创建对象,但具有更多的控制权。

    class SpecializedFactory : public GeneralFactory
    {
    private:
        virtual Object* CreateObject();
        virtual Object* DoCreateObject() = 0;
    };
    

    这个想法是为了 SpecializedFactory::CreateObject 使用 DoCreateObject 在实施过程中。但事实上,类可以从 SpecializedFactory 并覆盖 CreateObject 破坏了良好的意图。

    我所寻找的是可能的、有效的,还是程序员成为好公民并遵守阶级等级规则的唯一途径?

    什么是合适的替代方案?我正在使用C++03仅供参考。

    2 回复  |  直到 10 年前
        1
  •  3
  •   Christian Hackl    10 年前

    似乎在C++中(或者它是一般的OOP概念吗?) 总是虚拟的东西。

    我不会叫它 “一次虚拟始终虚拟” ,因为这听起来有点误导。虚拟性不是派生类的业务。虚拟功能的全部内容 基础 等级。它是基类,需要知道函数是否是虚拟的,并在必要时进行虚拟函数调用。派生类函数可以说 “我不再是虚拟的了!” 但谁在乎呢?此时已经通过虚拟函数调用调用了它。

    C++11 final 不会改变这种运行时行为,它只是防止在编译时重写。

    我所寻找的是可能的、有效的,还是唯一的方法 程序员要成为好公民并遵守阶级等级规则?

    在C++03中,最简单的方法是编写好文档,并在工作面试中只挑选优秀的程序员:)

    但这可能不是你想要的。这里的技术解决方案是将类设计更改为 具有a 关系 使整个课程成为最终课程的变通方法 存在于C++03中。

    所以,而不是 ConcreteSpecializedFactory 是-a SpecializedFactory ,完成它 专业化工厂 具有a SpecializedFactoryImplementation 。然后可以(可选地,为了更严格)使用 friend 要允许仅从前者调用后者,并且(这就是有趣的部分)可以使用 虚拟继承技巧 来自 C++ FAQ "How can I set up my class so it won't be inherited from?" 使整个 专业化工厂 班级决赛。

    class SpecializedFactoryImplementation
    {
    public:
        virtual ~SpecializedFactoryImplementation() {}
    
    private:
        SpecializedFactoryImplementation(SpecializedFactoryImplementation const &);
        SpecializedFactoryImplementation &operator=(SpecializedFactoryImplementation const &);
    
        friend class SpecializedFactory;
    
        Object* CreateObject()
        {
            return DoCreateObject();
        }
    
        virtual Object* DoCreateObject() = 0;
    };
    
    class SpecializedFactoryBase
    {
    private:
        friend class SpecializedFactory;
         SpecializedFactoryBase() {}
    };
    
    class SpecializedFactory : public GeneralFactory, private virtual SpecializedFactoryBase
    {
    // ...
    public:
        SpecializedFactory(SpecializedFactoryImplementation* impl) :
            m_impl(impl)
        {
            // null checking omitted for simplicity
        }
    private:
    
        // the GeneralFactory base class should not be copyable
        // anyway, so we do not have to worry about copy constructor
        // or assignment operator
    
        SpecializedFactoryImplementation* const m_impl;
    
        virtual Object* CreateObject()
        {
            return m_impl->CreateObject();
        }
    };
    

    然后将不编译以下内容:

    class SpecializedFactoryWrittenByEvilProgrammer : public SpecializedFactory
    {
    public:
        SpecializedFactoryWrittenByEvilProgrammer() : SpecializedFactory(0) {}
    private:
        virtual Object* CreateObject()
        {
            return 0;
        }
    };
    

    以下内容也不会编译:

    // somewhere outside of SpecializedFactory:
    SpecializedFactoryImplementation *s;
    s->CreateObject();
    
        2
  •  3
  •   Krypton    10 年前

    你需要的是 final 关键字:

    struct base {
       virtual void f();
    };
    struct derived : base {
       void f() final;       // virtual as it overrides base::f
    };
    struct mostderived : derived {
       //void f();           // error: cannot override!
    };