在工作讨论之后,我们似乎无法强制执行"逻辑"具有指针数据成员的类的const-correctness,如下所示:
class Widget {
public:
void Foo();
void FooConst() const;
};
class WidgetManager {
public:
WidgetManager() : _pW(std::shared_ptr<Widget>(new Widget())) { }
void ManagerFoo()
{
_pW->Foo(); // should be OK, will not compile if declared as "const Widget*"
_pW->FooConst(); // should be OK
}
void ManagerFooConst() const
{
_pW->Foo(); // should NOT be OK, will not compile if declared as "const Widget*"
_pW->FooConst(); // should be OK
}
void RegenerateWidget()
{
_pW = std::shared_ptr<Widget>(new Widget());
}
private:
std::shared_ptr<Widget> _pW;
};
可以看出,我们希望WidgetManager::ManagerFooConst()
无法调用WidgetManager
指针成员的非const函数,同时仍允许从WidgetManager
指针成员调用它们std::shared_ptr<const Widget>
的其他非const函数。这意味着,将指针声明为const Widget*
(即Widget
)已经结束。
此外,我们希望在经理的整个生命周期内让指针引用另一个WidgetManager
的选项,因此我们并不想将其作为数据成员保留(并且不能通过引用来保存它。)
当然,所有&#34;按位&#34;这里强制执行const-correctness,因为Widget
的数据成员不能在const方法中修改(包括_pW
指向的特定this
),但我们希望实现& #34;逻辑&#34; const-correctness甚至是尖锐的成员都无法修改。
我们唯一想到的是添加Widget
&#34;的const和非const&#34; getter;到class Widget {
public:
void Foo();
void FooConst() const;
Widget* GetPtr() { return this; }
const Widget* GetConstPtr() const { return this; }
};
:
void WidgetManager::ManagerFoo()
{
// shouldn't use "->" directly (lint?)
_pW->GetPtr()->Foo();
_pW->GetPtr()->FooConst();
//_pW->GetConstPtr()->Foo(); // this won't compile (good)
_pW->GetConstPtr()->FooConst();
}
void WidgetManager::ManagerFooConst() const
{
// shouldn't use "->" directly (lint?)
_pW->GetPtr()->Foo(); // shouldn't be used (lint?)
_pW->GetPtr()->FooConst(); // shouldn't be used (lint?)
//_pW->GetConstPtr()->Foo(); // this won't compile (good)
_pW->GetConstPtr()->FooConst();
}
直接使用这些代替箭头操作符:
operator->
但这太丑了,编译器肯定无法强制执行。
具体来说,尝试重置Widget*
和const Widget*
的{{1}}似乎无法改变任何内容:ManagerFooConst()
仍然可以调用_pW->Foo()
有没有办法实现这个目标?
答案 0 :(得分:2)
您可以使用(或重新实施)std::experimental::propagate_const
然后你的代码将是:
class Widget {
public:
void Foo();
void FooConst() const;
};
class WidgetManager {
public:
WidgetManager() : _pW(std::make_shared<Widget>()) {}
void ManagerFoo()
{
_pW->Foo(); // OK
_pW->FooConst(); // OK
}
void ManagerFooConst() const
{
_pW->Foo(); // not compile
_pW->FooConst(); // OK
}
private:
std::experimental::propagate_const<std::shared_ptr<Widget>> _pW;
};
答案 1 :(得分:1)
考虑通过成员函数访问authenticate
,该成员函数将AppComponent
的常量反映到指向对象上。
authenticate
您将在此处收到一个错误。
shared_ptr
答案 2 :(得分:0)
一个简单的解决方案是使const和非const管理器有两种不同的类型:
template<class TWidget>
class WidgetManager {
// ...
private:
std::shared_ptr<TWidget> _pW;
};
WidgetManager<const Widget> const_wm;
const_wm.ManagerFoo(); // fail: _pW->Foo(): call non-const function of *_pw: a const Widget.
答案 3 :(得分:0)
除了这里提出的内容之外,你还可以引入一个概念&#34;拥有指针&#34;基于共享指针:
template<class T>
class owning_ptr {
public:
owning_ptr(T* data) : mData{data} {}
// Put as many constructors as you need
T* operator->() { return mData.get(); }
const T* operator->() const { return mData.get(); }
private:
std::shared_ptr<T> mData;
};
此类具有与共享指针相同的功能,但具有不同的拥有数据的概念。
您可以像使用共享指针一样使用它:
class WidgetManager {
...
private:
owning_ptr<Widget> _pW;
}