一个类的抽象成员应该是指针还是引用?

时间:2015-12-16 18:25:53

标签: c++ dependency-injection abstract-class class-members

类的抽象成员应该是指针还是引用?

对于玩具示例,请说我有以下课程:

class SerializedFileProcessor {
public:
    std::string Process(std::string file) const {
        std::string text = deserializer.Deserialize(file);
        text = processor.Process(text);
        return serializer.Serialize(text);
    }

private:
    IDeserializer? deserializer;
    IProcessor? processor;
    ISerializer? serializer; 
};

其中(具体子类的实例)反序列化器,处理器和序列化器都被传递到这个类的构造函数中。

SerializedFileProcessor不拥有这些,不应删除它们。

这些类成员应该是指针还是引用?或者这种模式应该完全不同吗?

3 个答案:

答案 0 :(得分:1)

这几乎是依赖注入(/ inversion)的hello-world示例。

这里有一个类似的问题,有不同的解决方案:Dependency injection in C++11 without raw pointers

修改:我将原来的答案从这里移到了那个问题。

SerializedFileProcessor示例的原始答案:

仅使用指针(智能或原始)或甚至是普通的C ++引用的缺点是它们允许从const上下文中调用非const方法。

我提出了一个与std::reference_wrapper类似但不完全相同的包装器(缺少const安全访问器)。将T*替换为unique_ptrshared_ptr以获取拥有版本(还添加默认移动构造)。

  template<typename T>
  struct NonOwningRef{
    NonOwningRef() = delete;
    NonOwningRef(T& other) noexcept : ptr(std::addressof(other)) { };
    NonOwningRef(const NonOwningRef& other) noexcept = default;

    const T& value() const noexcept{ return *ptr; };
    T& value() noexcept{ return *ptr; };

  private:
    T* ptr;
  };

用法:

class SerializedFileProcessor {
public:
    std::string Process(std::string file) const {
        std::string text = deserializer.value().Deserialize(file);
        text = processor.value().Process(text);
        return serializer.value().Serialize(text);
    }

private:
    NonOwningRef<IDeserializer> deserializer;
    NonOwningRef<IProcessor> processor;
    NonOwningRef<ISerializer> serializer; 
};

答案 1 :(得分:0)

它们可以是,您必须只确保引用的对象在使用之前不会死亡(即通常它的生命周期应该超过SerializedFileProcessor生命周期)。

引用成员有一个缺点 - 实际上创建赋值运算符几乎是不可能的(所以如果你需要一个,那么你需要一个指针 - 即使对于具有引用成员的类,也有一些实际具有赋值的技术,但它们非常讨厌)。如果它们是可选的,那么它们需要是指针(引用不是可选的)。

答案 2 :(得分:-3)

如果您的班级不拥有它们,则不应该作为参考。使用指针并让所有者持有std::unique_ptr