2014-01-17 1 views
0

Недавно я работал с небольшим количеством звукового кода, и хотя для понимания вопроса не требуется опыт работы с доменом, я думаю, что это может помочь в моем намерении ,Ссылки, векторы, std :: vector :: at и легко используемые интерфейсы

У меня есть объект-контроллер с std :: vector объектов Audio_channel. Каждый аудиоканал в этом векторе поддерживает состояние каждого канала (воспроизведение, а не воспроизведение ...). Одна конкретная библиотека, которую я использую, работает с обратными вызовами, поэтому вы воспроизводите звук, который вы помечаете как «игра», и когда это делается, происходит обратный вызов, поэтому вы можете пометить его как «незанятый». Для целей этого примера предположим, что Audio_channel :: play_something() существует и работает так, как ожидалось: отметьте как воспроизведение и начните воспроизводить звук, ожидая обратного вызова, когда звук будет выполнен.

Во всяком случае, большую часть времени вы получите воспроизводить звук через объект контроллера, например:

int channel=0; 
audio_controller.play_some_sound(channel); //It would really do something like this->channels.at(0).play_something(); 

И это, конечно, работа с audio_controller действительно владеет этими Audio_channels.

Там будет время, когда вы хотите, канал, то все к себе и хотел бы сделать это:

Audio_channel c=audio_controller.get_me_this_channel(0); //This returns the channel by reference with vector.at(). Try and catch blocks are ommited. 
c.play_something(); 

И хотя он будет работать (так как она оборачивает библиотеку, которая не знает этих абстракций) Я знаю, факт, что этот Audio_channel является копией оригинала и, следовательно, не запрашивается с контроллера (поскольку любые изменения не отражаются).

Я всегда могу пойти:

Audio_channel& c=audio_controller.get_me_this_channel(0); 
c.play_something(); 

И на этот раз я получаю реальное дело, и любые изменения отражаются повсюду ... Дело в том, с точки зрения «вызывающий код» может быть нелогичным силу ссылка там - специально там, где никакая ошибка не будет передана компилятором, так как ошибка не существует. Всегда есть указатели, но я хотел бы держать их под поверхностью. Я думаю, что интеллектуальные указатели также являются опцией, но, опять же, я хотел бы сохранить его как можно ближе к исходному коду.

Какие еще варианты вы можете видеть здесь, что мне может не хватать ?. Я думал об обертке Audio_channel во что-то другое, что делает грязную справочную работу и возвращает копии этого другого интерфейса ... Я бы попадал в много перенаправления кода и методы, которые просто вызывают методы ссылочного канала, но хорошо ..

Как уже говорилось, есть ли что-то, что я могу потерять ?. Я работаю с недавним компилятором gcc, поэтому разрешено использование C++ X11. Большое спасибо.

+0

make 'get_me_this_channel' return reference – Gasim

+0

Фактический прототип Canal_audio & obtener_canal (int) throw(); Он уже возвращает ссылку. Спасибо, в любом случае. –

+1

«специально, где ошибка компилятора не будет устранена, так как ошибки не существует», было бы, если вы сделаете Audio_channel невозможным. Это вариант? Мне кажется, это имеет смысл, так как вы также говорите, что работа с копией имеет свои проблемы. – stijn

ответ

0

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

Что я сделал, это превратить Audio_channel в Audio_channel_nonpublic и оставить его закрытым для контроллера. Контроллер теперь возвращает класс оболочки вокруг Audio_channel_nonpublic (точно названный Audio_channel), который имеет ссылку на оригинал и получает право на копирование. Новый Audio_channel реализует тот же публичный интерфейс, что и Audio_channel_nonpublic, и пересылает каждый вызов указанному объекту. Таким образом, код клиента не должен изменяться вообще.

Результат работает, но есть много передовых деклараций и фрагментов кода, которые могут быть немного запутанными, когда я вернусь к ним через несколько месяцев ... Это документирует время !!.

Спасибо за ваши комментарии.

1

ошибка не будет когда-либо emmited компилятором, так как ошибки не существует

Если вы хотите здесь ошибку, изменить дизайн Audio_channel, с C++ 11 вы можете написать:

class Audio_channel 
{ 
    Audio_channel(const Audio_channel&) = delete; 
    Audio_channel& operator=(const Audio_channel&) = delete; 
    ... 
}; 
Audio_channel c=audio_controller.get_me_this_channel(0); 

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

Если вам действительно нужна семантика значений, как и ваш ответ, вы уже находитесь на правильном пути. Вы используете proxy pattern для ссылки на аудиоканал. Что-то вроде:

class Audio_channel_proxy 
{ 
public: 
    Audio_channel_proxy(Audio_channel& c) : m_channel(c) {} 
    void play_something() { m_channel.play_something(); } 
... 
private: 
    Audio_channel &m_channel; 
} 

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

Второй способ не является общим, но и не редкими. У этого есть потенциальная ошибка. Особенно если вы переименуете свой прокси-сервер с Audio_channel: это не самодокументируется.

Audio_channel c=audio_controller.get_me_this_channel(0); 

Эта линия предлагает уникальную собственность на канал, потому что это копия по значению. Но на самом деле это просто псевдоним канала, кто-то еще может изменить. Поэтому вы лучше документируете это (я бы начал с именования). Я думаю, вы уже это заметили. Каждый раз, когда я видел этот метод, по крайней мере один человек ошибался, пока не узнал его урок, включая меня. Далее вам необходимо реализовать и интерфейс интерфейса Audio_channel в прокси. Просто для синтаксического сахара, который не был вынужден писать ссылку, это не стоит того.

С другой стороны, прокси имеет реальное значение, если вам требуется другое поведение канала (или, по крайней мере, его распознавание), если оно вызвано через audio_controller или кто-то другой напрямую обращается к нему. Но начните с этого только в случае необходимости.

+0

Upvote, потому что я очень ценю время и знания :). Я немного переработал код, чтобы разместить удаление этих методов, и хотя он работает сам по себе, я снова разбился о стену, когда он заполнил вектор ... Без возможностей копирования эти вещи не могут быть назначены, и я не могу сделайте это мимо. Это позор, потому что мне действительно нужно иметь вектор из них (в зависимости от того, как выполняется программа, может быть изменение числа) ... Изменение внутреннего кода таким образом, что существует std :: vector , который связан с возвратом * vector.at (index) –

+0

позволяет ссылаться на ссылки.Это также приводит к некоторым странным идиомам, когда какой-либо другой объект должен временно отслеживать канал, который может измениться позже (вызывает указатели вокруг, но опять же имеет смысл и альтернативы, такие как сохранение индекса). Я не знаю, какое решение я выберу, но большое спасибо! –

+0

@ TheMarlboroMan, если вы хотите, чтобы вектор не копируемых объектов использовался для C++ 11, использует std :: vector >. Должен признаться, что до сих пор я с ним не работал, но, возможно, это отправная точка для вас. – DaBrain

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