我有一个Data类和一个提供访问Data的方法的Wrapper类。WrapperMutable类扩展Wrapper以添加修改Data的方法。
#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指针,并在可变上下文中使用它:
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的所有方法。
发布于 2015-11-10 20:49:10
继承表达了一种“某种”关系。
一致性不是一种“同类”的关系。
常量对象是一种与可变对象非常不同的东西。
shared_ptr本身的模型说明了如何表达这种关系。可变数据的shared_ptr可以转换为常量数据的shared_ptr,但反之亦然。
您可以这样表达这种关系:
#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;
}输出:
not const
const发布于 2015-11-10 20:52:53
如果提供对数据各方面的只读访问的一堆函数不需要增加shared_ptr,而只需要(const)访问指定的数据,那么下面的oop方法将会起作用:
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,因此它们可能无法复制它。更多的样板。
发布于 2015-11-10 20:56:03
我认为,在WrapperMutable中不需要shared_ptr<>,一个原始指针就可以了:
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<>将创建与原始指针相同的代码,正确地放置、删除所有位置。
https://stackoverflow.com/questions/33629801
复制相似问题