【问题标题】:Const constructor常量构造函数
【发布时间】:2015-07-24 11:09:53
【问题描述】:

是否有可能在 C++ 中实现类似构造函数的功能,它只允许创建 const 对象?

我正在考虑使用const 和非const 方法为接口创建一个装饰器类。从const 基础对象初始化装饰器应该只能产生 const 装饰器,但从非 const 初始化应该会产生一个功能齐全的装饰器。

struct A
{
    virtual void foo();         // requires non-const A
    virtual void bar() const;   // const method
};

class decorator : public A
{
private:
    std::shared_ptr<A> p_impl;
public:
    virtual void foo()          { p_impl->foo(); }
    virtual void bar() const    { p_impl->bar(); }

    // regular constructor
    decorator(std::shared_ptr<A> const & p)             : p_impl(p) {} 

    // hypothetical constructor that makes a const
    decorator(std::shared_ptr<A const> const & p) const : p_impl(p) {} 
};

void F(std::shared_ptr<A> const       & regular_a
     , std::shared_ptr<A const> const & const_a   )
{
    decorator regular_decorator(regular_a);
    regular_decorator.foo(); // all good
    regular_decorator.bar(); // all good

    decorator bad_decorator(const_a);   // compiler error
    // trying to use a const constructor to init a non-const object

    const decorator const_decorator(const_a); // all good
    const_decorator.foo(); // compiler error, foo is not const
    const_decorator.bar(); // all good

    // I have a lot of these in code that is beyond my control
    decorator bad_practice(const_cast<decorator&>(const_decorator));

    bad_practice.foo(); // all good
}

我怎样才能达到类似的效果?

【问题讨论】:

    标签: c++ class decorator


    【解决方案1】:

    我只能通过没有返回const 对象的构造函数,而是返回shared_ptr&lt;const decorator&gt; 的静态函数(命名构造函数)来实现此功能。这“编码”了类型的常量并禁止非常量调用:

    struct A
    {
        virtual void foo();         // requires non-const A
        virtual void bar() const;   // const method
    };
    
    class decorator : public A
    {
    private:
        std::shared_ptr<A> p_impl;
    public:
        virtual void foo()          { p_impl->foo(); }
        virtual void bar() const    { p_impl->bar(); }
    
        // regular constructor
        decorator(std::shared_ptr<A> const & p)             : p_impl(p) {} 
    
        static std::shared_ptr<decorator const> constDecorator(std::shared_ptr<A const> const & p) { return std::make_shared<decorator>(std::const_pointer_cast<A>(p)); } 
    };
    
    void F(std::shared_ptr<A> const       & regular_a
         , std::shared_ptr<A const> const & const_a   )
    {
        decorator regular_decorator(regular_a);
        regular_decorator.foo(); // all good
        regular_decorator.bar(); // all good
    
        decorator bad_decorator(const_a);   // compiler error
        // trying to use a const constructor to init a non-const object
    
        std::shared_ptr<const decorator> const_decorator = decorator::constDecorator(const_a); // all good
        const_decorator->foo(); // compiler error, foo is not const
        const_decorator->bar(); // all good
    
        // I have a lot of these in code that is beyond my control
        decorator bad_practice(const_cast<decorator&>(*const_decorator));
        bad_practice.foo(); // all good
    }
    

    您当然也可以通过声明另一个静态函数将shared_ptr 用于非常量装饰器,从而获得常量和非常量的相似使用模式。

    请注意,这将要求您删除复制构造函数和 operator= for decorator,因为它们将失去常量。但是,在您的带有假设 const 构造函数的版本中存在类似问题。

    我尝试过的另一种方法是使decorator 成为模板类并具有两种不同的类型:decorator&lt;A&gt; 和decorator&lt;const A&gt;,希望编译器不会实例化decorator&lt;const A&gt;::foo(),除非它被使用,但它会继续实例化即使不使用它。

    【讨论】:

    • 我会返回一个std::unique_ptr。如果所有者愿意,可以稍后共享。同样,我会将p_impl 设为std::unique_ptr。
    猜你喜欢
    • 2023-03-20
    • 2015-08-27
    • 2021-12-25
    • 2012-04-04
    • 2020-10-30
    • 1970-01-01
    • 2020-06-20
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多