我有一个Data
类和一个Wrapper
类,它提供了访问Data
的方法。 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(); }
};
问题当然是包裹const
对象的Data
- ness,这意味着WrapperMutable
无法修改它。
我考虑过将Wrapper
更改为接受并存储非const
Data
,但通常客户端本身只能访问const Data
,因此他们会被强制使用到const_cast
或复制以创建Wrapper
。
所以我能够实现这一目标的唯一方法是在const
类中保留一个非WrapperMutable
指针,并在可变上下文中使用它:
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
};
有更好的方法吗?显然,从WrapperMutable
派生Wrapper
是我的问题的根源,但我不想在Wrapper
中重新实现WrapperMutable
的所有方法。
答案 0 :(得分:1)
继承表示&#34;种类&#34;关系。
constness不是&#34;种类&#34;关系。
对于可变的东西来说,const是一种非常不同的东西。
shared_ptr本身的模型显示了如何表达这种关系。 shared_ptr到可变数据可以转换为const Data的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
答案 1 :(得分:1)
如果提供对数据方面的只读访问权限的一堆函数不需要递增get()
而只需要($query_builder = DB::table('table1');
// different than
$eloquent_builder = Table1Model::select()
)访问权限对于指向的数据,然后遵循oop方法将起作用:
shared_ptr
优势:您不需要另一份const
。
缺点:您现在使用其他方式不需要的虚拟功能。只读功能无法访问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;
};
,因此他们可能无法复制它。更多样板。
答案 2 :(得分:1)
我认为,shared_ptr<>
中不需要WrapperMutable
,原始指针会执行:
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<>
的唯一所有权。原因是,shared_ptr<>
与原始指针和unique_ptr<>
形成对比并不是免费的。它会重新获取参考计数器的额外增量和减量,并且当您取消引用它时通常会增加一个间接级别。另一方面,unique_ptr<>
将创建与原始指针相同的代码,并且正确地删除所有地方。
答案 3 :(得分:1)
setText()