const корректность для указателей
class InnerTest
{
public:
InnerTest() {};
~InnerTest() {};
void some_non_const_method() { std::cout << ++m_data << std::endl; }
private:
int m_data{ 0 };
};
class Test
{
public:
Test() {};
~Test() {};
// error C2662: 'void InnerTest::some_non_const_method(void)': cannot convert 'this' pointer from 'const InnerTest' to 'InnerTest &'
void foo() const { m_test.some_non_const_method(); };
void bar() const { m_ptest->some_non_const_method(); };
private:
InnerTest m_test;
std::unique_ptr<InnerTest> m_ptest{ std::make_unique<InnerTest>() };
};
int main()
{
Test t1;
t1.foo();
t1.bar();
return 0;
}
Итак есть примерно такой код, как можно добиться const корректности при использовании указателей для константных методов?
Ответы (2 шт):
Компилятор прав - у вас член имеет тип
unique_ptr<InnerTest>
и его значение вы не меняете. Если вы хотите явно указать, что там у вас константный указатель - то скажите об этом прямо:
unique_ptr<const InnerTest>
Все, вообще-то корректно - const в функции-члене относится к объекту класса, так что m_test, входящий в объект класса, действительно не может вызывать неконстантный метод. Но какой-то левый, не пойми где находящийся объект InnerTest - с какой стати ему запрещать вызывать неконстантный метод?...
В С++ const корректность не подразумевает транзитивности, т.е. const применяется только к самому объекту (указателю), но не распространяется на объекты, на которые тот указывает. А умные указатели из стандартной библиотеки просто мимикрируют поведением обычных указателей. Однако несложно реализовать обертку, имитирующую транзитивное поведение, для этого следует лишь добавить соотв. const перегрузки: online compiler
template< typename x_Value > class
t_TransitivePtr
{
private: x_Value * m_p_value;
public: explicit t_TransitivePtr(x_Value * p_value): m_p_value{p_value} {}
public: x_Value & operator * (void) { return *m_p_value; }
public: x_Value const & operator * (void) const { return *m_p_value; }
public: x_Value * operator -> (void) { return m_p_value; }
public: x_Value const * operator -> (void) const { return m_p_value; }
};
#include <string>
class
t_Test
{
private: t_TransitivePtr<::std::string> m_ptr;
public: explicit t_Test(::std::string & value): m_ptr{&value} {}
public: void Method(void) { m_ptr->clear(); } // OK
public: void ConstMethod(void) const { m_ptr->clear(); } // Error
};
В разных других языках может быть реализовано другое поведением. Например в языке D const полностью транзитивный; это подразумевает, что const указатель в принципе не может указывать на не const объект.