Я пытаюсь лучше понять, как работает const-correctness
и более конкретно, когда имеешь дело с классами, члены которых основаны на containers
и smart pointers
.
Я предполагаю, что свойство const-correctness
одинаково независимо от членов класса. Тем не менее, поскольку у меня есть некоторые трудности, чтобы четко понять, что происходит
Я решил попросить вас совета.
Итак, вот контекст. У меня есть класс ShapeContainer
, который имеет в качестве закрытого члена вектор умных указателей.
Класс Shape
является абстрактным и имеет следующую виртуальную функцию virtual float doSomething();
, которая затем переопределяется производными классами. Обратите внимание, что это неконстантная функция класса.
Соответствующая часть кода приведена ниже:
class ShapeContainer{
public:
typedef std::shared_ptr<Shape> ShapePtr;
typedef std::vector<ShapePtr> ShapePtrContainer;
// .......
const ShapePtr & operator[]( int ) const { return m_vect[index]; }; // const version
// ShapePtr & operator[]( int ) { return m_vect[index]; }; // non-const version
// .......
private:
ShapePtrContainer m_vect;
};
class Shape{
public:
// ...
virtual float doSomething() = 0;
};
Вот мои вопросы.
Q1. Почему мне разрешено вызывать функцию doSomething()
следующим образом: int index = 0; float tmp = container1[index]->doSomething();
(с ShapeContainer container1=createBasicShapes();
)?
Насколько я понимаю, после вызова функции const ShapePtr operator[] const
мы получим указатель const
на объект Shape
, однако виртуальный doSomething()
функция не const. Итак, как ссылка на const-объект может вызывать неконстантную функцию?
Q2. Вызывая функцию doSomething()
как ранее проиллюстрированную (float tmp =container1[index]->doSomething();
) и путем добавления non-const
версии operator[]
, это latter
тогда вместо const-version
вызывается перегруженная версия. Почему это так?
Теперь вместо класса ShapeContainer
у меня теперь есть новый класс с именем ShapeContainerInfo
, в котором все еще есть vector
, но промежуточного класса ShapeInfo
(в котором в качестве члена класса используется интеллектуальный указатель). ).
class ShapeContainerInfo{
public:
typedef std::vector<ShapeInfo> ShapeContainer;
const ShapeInfo & operator []( int index) const { return m_vect[index]; };
// ShapeInfo & operator []( int index) { return m_vect[index]; }; // non-const version
private:
ShapeContainer m_vect;
};
class ShapeInfo{
public:
typedef std::shared_ptr<Shape> ShapePtr;
// ...
float doSomething(){ return m_ShapePtr->doSomething(); };
private:
ShapePtr m_ShapePtr;
int m_nID;
};
Q3. Когда я вызываю float tmp = container2[i].doSomething();
, я получаю следующую ошибку компилятора: error C2662: 'ShapeInfo::doSomething' : cannot convert 'this' pointer from 'const ShapeInfo' to 'ShapeInfo &'
.
Однако, когда я добавляю non-const
версию перегруженного operator []
, ошибка компилятора исчезает. Итак, зачем мне действительно нужно non-const operator[]
для ShapeContainerInfo
, а не для ShapeContainer
?
Q4. Если m_vect
private
элемент ShapeContainerInfo
теперь установлен как public
member и только определена const-версия operator[]
(не non-const
one), то есть нет сообщений об ошибках компилятора. Почему это? например после установки m_vect
в качестве участника публичного класса: float tmp = info.m_vect[i].doSomething();
Q5. Как я могу правильно определить классы ShapeInfo
и ShapeContainerInfo
, чтобы мне нужно было определить только const-version
из operator[]
и при этом иметь возможность вызывать функцию float doSomething()
?
Для тех, кто интересуется всем примером кода, вы можете найти его здесь .
Разъяснения, предложения всегда приветствуются :-)
Merci!