2013-06-04 2 views
3

Прошло некоторое время с тех пор, как я перешел на C++, но я хочу убедиться, что я придерживаюсь лучших практик, когда я это делаю, в том числе и const-correct.Только C++ Разрешить задание переменной-члена только

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

class Screen 
{ 
public: 
    Clear(); 
} 

и

class Game 
{ 
private: 
    Screen* screen; 

protected: 
    const Screen* GetScreen() const; 
} 

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

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

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

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

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

+4

Похоже, вы хотите, чтобы 'screen' был' Screen & 'или' Screen * const' вместо 'const Screen *'. – Casey

ответ

0

Понятие «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 представляется монолитным объектом singleton, который содержит все, что в вашей программе. Если это так, представляется сомнительным, что было бы полезно когда-либо передавать ссылку на Game - или на объект, полученный из него, - делая различие между и Game& несколько спорным. Если это так, const-correctness не имеет никакой полезности, и вы избавитесь от головной боли, если просто сделаете все члены Game неконстантными.

+0

Я думаю, что сделаю так, как вы предлагаете, и сделайте членов 'Game' неконстантными. Хотя это и не синглтон, он должен быть эффективной точкой входа. Например. основная функция создаст новый объект 'Game' и вызовет его только открытый метод' Run() ', а остальная часть будет обработана оттуда. Производные классы 'Game' будут отвечать за любые другие объекты и не должны иметь доступа к игре. Я, вероятно, просто переусердствовал, когда мне не нужны вещи, чтобы быть const. –

0

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

class Game 
{ 
    Screen *screen; 

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

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

-1

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

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

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

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

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

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

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

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

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

 Смежные вопросы

  • Нет связанных вопросов^_^