是否可以在c ++中强制传递依赖对象的constness

问题描述 投票:3回答:3

这是我想要阻止的:

class Dep; //for "dependency"

class C {
  private: 
    const Dep& dep_; //or std::shared_ptr if I want to guarantee proper lifetime of dependency
  public:
    C(const Dep& dep) : dep_(dep){}
}

Dep d(Arg arg);
C obj(d); //obj can't change d
d.some_non_const_method(); //But it's creator can :(

我想得到的是,创建C对象的唯一正确方法是这样的:

Dep d(Arg arg);
d.some_non_const_method();
const Dep d1(d); //or move constructor if appropriate
C obj(d1); //Object d1 must be const!
d1.some_non_const_method(); //compile error, so obj can be sure that the dependency he's got is really const.

有没有办法通过语法强制执行此操作?

附:依赖是为了共享,所以我不能在这里使用std::unique_ptr

c++ dependency-injection const
3个回答
2
投票

我认为没有办法通过语法直接强制执行此操作。

问题是任何Dep&都可以自由转换为const Dep&。正如你正确地指出采取const Dep &d并不意味着它是恒定的,而是承诺你的功能永远不会修改d

当其他答案巧妙地使用重载和删除方法来创建错误时,只要直接传递非const Dep,当从其他地方传递const Dep &时,这些方法会失败。

// this could be arbitrarily complex and nested
std::unique_ptr<C> makeC(const Dep &d) {
     return std::make_unique<C>(d);
} 

void test() {
    Dep nonConstDep;
    auto pC = makeC(nonConstD); // conversion to const & is legal
    nonConstDep.mutate(); // Nooo!
}

你需要的是一个不可变的dep类,它不允许变异和转换。

由于我不知道您是否可以更改Dep类以及如何在程序的其他部分使用它,我建议使用此解决方案:

创建一个ImmutableDep包装器,它有一个私人const Dep。然后你可以限制你的类只采用ImmutableDep引用。

class ImmutableDep {
     const Dep dep_;

public:
     inline const Dep &get() const { return dep_; }
};

class C {
     const Dep &dep_;
public:
     // we know that an ImmutableDep's dep really is immutable
     C(const ImmutableDep &dep) : dep_(dep.get()) {}
}

通过这种方式,您可以根据需要将const或非const引用传递给ImmutableDep,始终保证私有包装的Dep是不可变的。

如果你只需要在有限的“构造”阶段修改Dep,我建议使用Builder pattern并在完成后创建一个不可变对象,也许将任何大的东西移动到不可变对象中。


5
投票

如果我正确理解你的问题,你只想接受一个const参数,并希望在传递非const参数时出错。

最简单的方法应该是将非const版本标记为delete

class C {
  private:
    const Dep& dep_;
  public:
    C(const Dep& dep) : dep_(dep){}
    C(Dep &) = delete;
};

然后:

Dep d;
C obj(d); // Error, deleted function selected

const Dep d1(d);
C obj(d1); // ok

1
投票

形式的东西

class C
{
    C() = default;
    friend class D;
};

class D
{
    public:
    C create_C() = delete;
    C create_C() const {return C};
};

会做的。我已经建造了C privateD可以访问它,因为它是friendCconst的非create_C超载被删除。

© www.soinside.com 2019 - 2024. All rights reserved.