После обсуждения на работе мы, похоже, не можем навязать «логическую» const-корректность для класса, имеющего указатели-члены-данные, как таковые:
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
, в то же время позволяя вызывать их из других неконстантных функций WidgetManager
.Это означает, что объявление указателя как std::shared_ptr<const Widget>
(то есть const Widget*
) отсутствует.
Кроме того, мы хотели бы, чтобы опция указателя указывала на другой Widget
в течение срока службы менеджера, поэтомуна самом деле мы не хотим хранить его как элемент данных (и не можем хранить его по ссылке).
Конечно, здесь применяется вся «побитовая» const-правильность, так как нет элементов данныхWidgetManager
может быть изменено изнутри методами const (включая конкретный Widget
, на который указывает _pW
), но мы бы хотели достичь "логической" правильности const, даже если указанные члены не могут быть изменены.
Единственное, что мы придумали, - это добавление const и неконстантных "getter of this
" к Widget
:
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*
некажется, что-то изменилось: ManagerFooConst()
все еще мог звонить _pW->Foo()
.
Есть ли способ достичь этого?