const — C ++ Only Разрешить установку переменной-члена один раз

Прошло много времени с тех пор, как я перешел на C ++, но я хочу убедиться, что придерживаюсь лучших практик, в том числе и правильности.

В настоящее время я создаю библиотеку кода для игрового фреймворка, и у меня есть следующие классы (обобщены для простоты):

class Screen
{
public:
Clear();
}

а также

class Game
{
private:
Screen* screen;

protected:
const Screen* GetScreen() const;
}

Для краткости я опустил все остальное, но достаточно сказать, что Game класс отвечает за создание Screen экземпляр класса. После того, как он создан, к нему можно получить доступ только через GetScreen() метод.

Идея состоит в том, что при создании новой игры я бы унаследовал от этого базового класса, поэтому, например, во время цикла рендеринга я бы хотел очистить экран, чтобы перерисовать следующий кадр. Теперь в моих вышеприведенных определениях Clear() метод не может быть вызван при использовании GetScreen() метод, потому что это не const, Метод clear фактически изменил бы внутреннюю работу класса (в силу того факта, что ранее отображаемое изображение было очищено), поэтому я оставил const объявление вне определения. Если бы я сделал это const тогда я должен был бы иметь некоторые из внутренней работы Screen класс как mutable но из того, что я прочитал, это не было бы очень правильным.

Итак, у меня есть две части к моему вопросу. Должен ли я изменить void Clear() в void Clear() const и сделать части внутренней работы mutable?

Или это альтернатива, которая позволила бы мне сделать screen член Game класс устанавливается только один раз Game класс, чтобы я мог получить доступ к неконстантным функциям-членам в течение остальной части времени выполнения программы.

Спасибо за любую помощь.

3

Решение

Понятие «const» полезно для указания того, что внутреннее состояние объекта не должно быть изменяемым.

void f(const Object& o)
{
// 'o' cannot be modified
}

Возможность пометить нестатический элемент как const позволяет обеспечить соблюдение, что держатели const ссылка на объект не может изменить внутреннее состояние. Например, в следующем сценарии Object имеет аксессуар str который возвращает ссылку на внутреннее состояние, которое имеет как неконстантные, так и константные перегрузки:

struct Object
{
// non-const: caller can modify internal state
std::string& str();

// const: caller cannot modify internal state
const std::string& str() const;
};

Неконстантная перегрузка допускает изменение внутреннего состояния, но может вызываться только при неконстантной ссылке на объект; Перегрузка const не позволяет изменять внутреннее состояние и может использоваться как с объектными, так и с неконстантными ссылками.

В сценарии, который вы представляете, Game кажется монолитным одиночка объект, который содержит все в вашей программе. Если это так, то представляется сомнительным, что было бы полезно когда-либо передавать ссылку на Game — или к объекту, производному от него — делая различие между const Game& а также Game& несколько спорный Если это так, const-правильность не имеет смысла, и вы избавите себя от головной боли, если просто сделаете все члены Game неконстантная.

0

Другие решения

поскольку Game::screen является закрытым, к нему не может получить доступ производный класс. Пока звонящий GetScreen() может получить доступ к Screen объект, он не может изменить то, что Gameхранится screen указывает на. Таким образом, вы прекрасно с, например, обеспечивая эти две перегрузки:

class Game
{
Screen *screen;

protected:
const Screen* GetScreen() const;
Screen* GetScreen();
};

Ни один из них не позволяет производному классу изменять screen сам указатель, поэтому он не может «сбросить» его, чтобы указать куда-то Game не хотел бы, чтобы это указывало.

0

Я настоятельно рекомендую вам обновить ваши знания указателей в C ++. В наши дни почти нет причин использовать сырые указатели.

Чтобы ответить на вопрос напрямую, Game.GetScreen() Функция будет хотеть ‘const’ по-разному, в зависимости от того, как именно вы хотите, чтобы она себя вела

Если вы вернете const Screen* вы возвращаете указатель на объект Screen, который является постоянным (не может быть изменен). Обычно вы хотели бы сделать такую ​​функцию const, позволяющей вызывать ее для объекта Game, который сам по себе является константой. Если у кого-то есть неконстантный объект Game, вы можете позволить ему получить объект Screen, который он затем может изменить, просто вернув Screen*,

Тем не менее, я возвращаюсь к своей начальной точке, вы не должны использовать сырые указатели.

Первоначально, вы должны просто хранить объект Screen по значению и возвращать ссылки, давая вам класс в соответствии с:

Class Game{
Screen screen;
public:
const Screen& GetScreen() const{ return screen; }
Screen& GetScreen(){ return screen; }
};

Может показаться, что вы копируете объект Screen для его возврата, но типы возврата гарантируют, что вы возвращаете ссылку на тот же экранный объект, а не на копию.

Если вам действительно нужно динамическое создание объекта Screen (т. Е. Вы не можете создать его ни до, ни во время создания объекта Game), вам следует использовать std::unique_ptr<Screen>, Это можно использовать очень похоже на необработанный указатель, но позаботится о многих функциональных возможностях для вас. Тем не менее, вы хотите поделиться доступом к этому указателю экрана, поэтому вы, вероятно, хотите использовать std::shared_ptr<Screen> и вернуться std::weak_ptr<Screen> из функции get. Слабый_птр можно использовать, чтобы разрешить другим доступ, но ваш первоначальный игровой объект все еще владеет Экран объекта.

Короче говоря, сохраняйте объект Screen по значению и возвращайте ссылки на него.

-1