Warning: file_get_contents(/data/phpspider/zhask/data//catemap/8/design-patterns/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C++ 在非虚拟接口习惯用法中添加不变量_C++_Design Patterns_Idioms_Template Method Pattern_Non Virtual Interface - Fatal编程技术网

C++ 在非虚拟接口习惯用法中添加不变量

C++ 在非虚拟接口习惯用法中添加不变量,c++,design-patterns,idioms,template-method-pattern,non-virtual-interface,C++,Design Patterns,Idioms,Template Method Pattern,Non Virtual Interface,假设我使用NVI习惯用法具有以下层次结构: class Base { public: virtual ~Base() {} void foo() { cout << "Base::foo" << endl; foo_impl(); } private: virtual void foo_impl() = 0; }; class A : public Base { private:

假设我使用NVI习惯用法具有以下层次结构:

class Base
{
    public:
        virtual ~Base() {}
        void foo() { cout << "Base::foo" << endl; foo_impl(); }

    private:
        virtual void foo_impl() = 0;
};

class A : public Base
{
    private:
        virtual void foo_impl() { cout << "A::foo_impl" << endl; }
};
类基
{
公众:
虚拟~Base(){}

void foo(){cout在我的理解中,NVI是一种防止/阻止向非虚拟基方法添加不变量的方法,因此,此时您想要添加不变量的事实表明NVI或者根本不是您想要的模式,或者您可能想要重新构造您的设计,以便不需要添加此类不变量

也就是说,除了简单地将以前的非虚拟界面虚拟化之外,还可以使用C++11中的最后一个关键字:

class Base
{
    public:
        virtual ~Base() {}
        virtual void foo() { base_foo(); foo_impl(); }

    protected:
        void base_foo() { cout << "Base::foo" << endl; }
        virtual void foo_impl() = 0;
};

class SpecialBase : public Base
{
    public:
        virtual void foo() final // note the use of 'final'
        { base_foo(); specialbase_foo(); foo_impl(); }

    protected:
        void specialbase_foo() { cout << "SpecialBase::foo" << endl; }
};

class B : public SpecialBase
{
    private:
        virtual void foo_impl() { cout << "B::foo_impl" << endl; }
};
类基
{
公众:
虚拟~Base(){}
虚拟void foo(){base_foo();foo_impl();}
受保护的:

void base_foo(){cout这篇文章是向我建议的,类似于我前几天浏览的与NVI相关的内容,因此necro

我建议在基类中添加一个检查添加机制,这样派生类就可以添加需求。只要可以使用基类访问函数测试需求,这是一种非常简单的方法,否则您的特殊MyInvariant类必须动态转换doCheckInvariantOK()的基参数让不变量工作

编辑:我理解“不变量”与foo()的前置和后置条件一致,就像在正式验证中一样。如果您想在base_foo()之前和/或之后添加功能,我认为您实际上在追求什么,您可以用类似的方式来做

class Base
{
public:
    virtual ~Base() {}
    void foo() 
    { 
        cout << "Base::foo" << endl;

        //Can use invariants as pre and/or postconditions for foo_impl
        for(const std::unique_ptr<InvariantBase>& pInvariant : m_invariants)
        {
            //TODO cout << "Checking precondition " << pInvariant->GetDescription() << endl;
            if(!pInvariant->CheckInvariantOK(*this))
            {
                //Error handling
            }
        }
        foo_impl(); 
    }

protected:
    void AddInvariant(std::unique_ptr<InvariantBase>&& pInvariant)
    {
       m_invariants.push_back(std::move(pInvariant));
    }
    struct InvariantBase
    {
        bool CheckInvariantOK(const Base& base)
        {
            return doCheckInvariantOK(base);
        }
        private:
            virtual bool doCheckInvariantOK(const Base& base) = 0;
    };

private:
    std::list<std::unique_ptr<InvariantBase>> m_invariants;
    virtual void foo_impl() = 0;
};

class A : public Base
{
private:
    virtual void foo_impl() { cout << "A::foo_impl" << endl; }
};

class SpecialBase : public Base
{
public:
     SpecialBase() 
        : Base()
     {
        AddInvariant(std::unique_ptr<MyInvariant>(new MyInvariant() ) );
     }
private:
    void foo_impl() { cout << "SpecialBase::foo" << endl; bar_impl(); }
    virtual void bar_impl() = 0;

    struct MyInvariant : public InvariantBase
    {
        virtual bool doCheckInvariantOK(const Base& base) override
        {
            //TODO: special invariant code
        }
    };

};

class B : public SpecialBase
{
private:
    virtual void bar_impl() { cout << "B::bar_impl" << endl; }
};
类基
{
公众:
虚拟~Base(){}
void foo()
{ 

cout“因为我不想为添加到层次结构中的每个派生基添加方法(使用不同的名称)”我不确定这是否是一个坏主意。毕竟,你想要添加不变量,即派生类也需要维护这些新的不变量。考虑到你的编辑,我几乎想知道装饰器模式是否会为你提供你想要的自定义层。我理解你的观点,而且很可能NVI不是我想要的但是,我正在寻找一种更通用的习惯用法,而不仅仅是有一个可选的定制点……在我的层次结构中,SpecialBase是必需的,它不仅覆盖了foo()的实现。也可能有从SpecialBase派生的基类会再次重新实现foo()…所以我真的在寻找一种更通用的设计模式。我编辑了我的问题,以添加我正在寻找的真实工作流。有趣的是,我个人会选择一个
std::vector
:然后你就可以将不变量注册为lambda表达式,它可以从派生构造函数中捕获它们的上下文,从而消除对downca的需要sting.@Quentin:你能详细说明一下吗?lambda表达式如何知道它在doCheckInvariantOK()中的构造上下文?我的意思是以
AddInvariant([]{return/*check*/;})结尾
内置
SpecialBase::SpecialBase
。lambda可以使用正确的静态类型捕获
,然后通过
std::function
而不是OO多态性来完成类型擦除。
Base <- A
     <- B
     <- SpecialBase <- C
                    <- D
                    <- VerySpecialBase <- E
     <- StrangeBase <- F
class Base
{
    public:
        virtual ~Base() {}
        virtual void foo() { base_foo(); foo_impl(); }

    protected:
        void base_foo() { cout << "Base::foo" << endl; }
        virtual void foo_impl() = 0;
};

class SpecialBase : public Base
{
    public:
        virtual void foo() final // note the use of 'final'
        { base_foo(); specialbase_foo(); foo_impl(); }

    protected:
        void specialbase_foo() { cout << "SpecialBase::foo" << endl; }
};

class B : public SpecialBase
{
    private:
        virtual void foo_impl() { cout << "B::foo_impl" << endl; }
};
class Base
{
    public:
        virtual ~Base() {}
        virtual void foo() { base_foo(); bar_impl(); foo_impl(); }

    protected:
        void base_foo() { cout << "Base::foo" << endl; }
        virtual void bar_impl() {} // bar_impl is an optional point of customization
                                   // by default it does nothing

        virtual void foo_impl() = 0; // foo_impl is not optional derived classes
                                     // must implement foo_impl or else they will be abstract
};

class B : public Base
{
    private:
        virtual void bar_impl() { cout << "SpecialBase::foo" << endl; }
        virtual void foo_impl() { cout << "B::foo_impl" << endl; }
};
class Base
{
public:
    virtual ~Base() {}
    void foo() 
    { 
        cout << "Base::foo" << endl;

        //Can use invariants as pre and/or postconditions for foo_impl
        for(const std::unique_ptr<InvariantBase>& pInvariant : m_invariants)
        {
            //TODO cout << "Checking precondition " << pInvariant->GetDescription() << endl;
            if(!pInvariant->CheckInvariantOK(*this))
            {
                //Error handling
            }
        }
        foo_impl(); 
    }

protected:
    void AddInvariant(std::unique_ptr<InvariantBase>&& pInvariant)
    {
       m_invariants.push_back(std::move(pInvariant));
    }
    struct InvariantBase
    {
        bool CheckInvariantOK(const Base& base)
        {
            return doCheckInvariantOK(base);
        }
        private:
            virtual bool doCheckInvariantOK(const Base& base) = 0;
    };

private:
    std::list<std::unique_ptr<InvariantBase>> m_invariants;
    virtual void foo_impl() = 0;
};

class A : public Base
{
private:
    virtual void foo_impl() { cout << "A::foo_impl" << endl; }
};

class SpecialBase : public Base
{
public:
     SpecialBase() 
        : Base()
     {
        AddInvariant(std::unique_ptr<MyInvariant>(new MyInvariant() ) );
     }
private:
    void foo_impl() { cout << "SpecialBase::foo" << endl; bar_impl(); }
    virtual void bar_impl() = 0;

    struct MyInvariant : public InvariantBase
    {
        virtual bool doCheckInvariantOK(const Base& base) override
        {
            //TODO: special invariant code
        }
    };

};

class B : public SpecialBase
{
private:
    virtual void bar_impl() { cout << "B::bar_impl" << endl; }
};