首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >通过扩展添加可变性

通过扩展添加可变性
EN

Stack Overflow用户
提问于 2015-11-10 20:17:54
回答 4查看 80关注 0票数 3

我有一个Data类和一个提供访问Data的方法的Wrapper类。WrapperMutable类扩展Wrapper以添加修改Data的方法。

代码语言:javascript
复制
#include <memory>
using namespace std;

class Data {
public:
    void update();  // non-const method which modifies internal state of Data
};

class Wrapper
{
public:
  Wrapper(shared_ptr<Data const> data) : myData(data) {}  // accepts const pointer
  // ...bunch of functions providing read-only access to aspects of the Data...
protected:
  shared_ptr<Data const> myData;  // stores const pointer
};

// Extend Wrapper with methods to modify the wrapped Data.
class WrapperMutable : public Wrapper
{
public:
  WrapperMutable(shared_ptr<Data> data) : Wrapper(data) {}

  // ERROR: invoking non-const method on const object:
  void updateData() { myData->update(); } 
};

当然,问题出在包装的Data对象的const-ness上,这意味着WrapperMutable不能修改它。

我考虑将Wrapper更改为接受和存储非const Data,但通常客户端本身只能访问const Data,因此它们将被迫使用const_cast或copy来创建Wrapper

所以我能做到这一点的唯一方法是在WrapperMutable类中保留一个额外的非const指针,并在可变上下文中使用它:

代码语言:javascript
复制
class WrapperMutable : public Wrapper
{
public:
  WrapperMutable(shared_ptr<Data> data) : Wrapper(data), myMutableData(data) {}

  // Use myMutableData instead of the const myData
  void updateData() { myMutableData->update(); }

private:
  shared_ptr<Data> myMutableData;  // non-const pointer to the same Data as in Wrapper
};

有没有更好的方法?显然,从Wrapper派生WrapperMutable是我的问题的根源,但我也不想在WrapperMutable中重新实现Wrapper的所有方法。

EN

回答 4

Stack Overflow用户

发布于 2015-11-10 20:49:10

继承表达了一种“某种”关系。

一致性不是一种“同类”的关系。

常量对象是一种与可变对象非常不同的东西。

shared_ptr本身的模型说明了如何表达这种关系。可变数据的shared_ptr可以转换为常量数据的shared_ptr,但反之亦然。

您可以这样表达这种关系:

代码语言:javascript
复制
#include <iostream>
#include <memory>

struct Data
{
};

struct const_data_wrapper
{
    const_data_wrapper(std::shared_ptr<const Data> p) : _impl(std::move(p)) {}

    void which() const {
        std::cout << "const" << std::endl;
    }

private:
    std::shared_ptr<const Data> _impl;
};

struct data_wrapper
{
    data_wrapper(std::shared_ptr<Data> p) : _impl(std::move(p)) {}

    const_data_wrapper as_const() const {
        return const_data_wrapper(_impl);
    }

    void which() const {
        std::cout << "not const" << std::endl;
    }

private:
    std::shared_ptr<Data> _impl;
};

using namespace std;

auto main() -> int
{
    auto w1 = data_wrapper(make_shared<Data>());
    auto w2 = w1.as_const();

    w1.which();
    w2.which();

    return 0;
}

输出:

代码语言:javascript
复制
not const
const
票数 1
EN

Stack Overflow用户

发布于 2015-11-10 20:52:53

如果提供对数据各方面的只读访问的一堆函数不需要增加shared_ptr,而只需要(const)访问指定的数据,那么下面的oop方法将会起作用:

代码语言:javascript
复制
class BaseWrapper {
public:
    // ...bunch of functions providing read-only access to aspects of the Data...
protected:
    virtual const Data* getData() = 0;
    virtual ~BaseWrapper(){}
};

class WrapperConst: public BaseWrapper {
public:
   WrapperConst(shared_ptr<Data const> data) : myData(data) {}
protected:
    const Data* getData() {
        return myData.get();
    };
private:
    shared_ptr<Data const> myData;
};

class WrapperMutable : public BaseWrapper {
public:
    WrapperMutable(shared_ptr<Data> data) : myData(data) {}
    void updateData() { myData->update(); }
protected:
   const Data* getData() {
        return myData.get();
    };
private:
    shared_ptr<Data> myData;
};

优点:您不需要另一个shared_ptr副本。

缺点:您现在使用了原本不需要的虚拟函数。只读函数不能访问shared_ptr,因此它们可能无法复制它。更多的样板。

票数 1
EN

Stack Overflow用户

发布于 2015-11-10 20:56:03

我认为,在WrapperMutable中不需要shared_ptr<>,一个原始指针就可以了:

代码语言:javascript
复制
class WrapperMutable : public Wrapper
{
public:
  WrapperMutable(Data* data):
    Wrapper{shared_ptr<Data const>{data}},
    myMutableData{data} {}

  // Use myMutableData instead of the const myData
  void updateData() { myMutableData->update(); }

private:
  Data* myMutableData;  // non-const pointer to the same Data as in Wrapper
};

至少这使您不必递增和递减引用计数器。

从软件设计的角度来看,你确定WrapperMutable“是”Wrapper吗?我的直觉告诉我,你在某处打破了单一责任原则。这是我见过的设计问题的最主要原因之一。

顺便说一句,如果你真的需要一个shared_ptr<>,请重新考虑一下。作为垃圾收集的替代品,它经常被过度使用。当您真的想声明共享所有权时,可以使用它。如果没有所有权,则首选原始指针;如果唯一所有权,则首选unique_ptr<>。原因是,与原始指针和unique_ptr<>相比,shared_ptr<>并不是免费的。它需要引用计数器的一个额外的增量和减量,并且当你取消引用它时,通常需要一个额外的间接层。另一方面,unique_ptr<>将创建与原始指针相同的代码,正确地放置、删除所有位置。

票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/33629801

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档