Использование ссылок на классы для изменения открытых членов в другом классе

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

#include <iostream>
using namespace std;

class String
{
    public:
    private:
};

class ClassTwo
{
    public:
        int memberVariable;
    private:
};

class ClassOne
{
    public:
        ClassOne (ClassTwo&, String&);
        ~ClassOne();

    private:
        ClassTwo& classTwoReference;
        String& stringReference;
};

ClassOne::ClassOne (ClassTwo& two, String& string)
    : classTwoReference (two), stringReference (string)
{
    two.memberVariable = 3;
}

ClassOne::~ClassOne()
{
}

int main()
{
    String stringObject;
    ClassTwo classTwoObject;
    ClassOne classOneObject (classTwoObject, stringObject);
}

В JUCE, который является API, который я использую для кодирования плагина VST, есть строковый класс, который JUCE называет «String». Я точно не знаю, что делает конструктор, но вы можете использовать что-то подобное для создания объекта String.

String newString("string");

ClassTwo в моем случае — это класс AudioProcessor, у которого есть общедоступная переменная-член, к которой я могу получить доступ из ClassOne, как это.

two.memberVariable = 3;

В моем случае ClassOne — это настраиваемый компонент (я назвал его PixelSlider), который я использую в своем графическом интерфейсе. Он использует прослушиватель ползунка для проверки состояния ползунка и изменения переменной-члена в ClassTwo (AudioProcessor). Я могу сделать это хорошо, используя описанный выше метод, но проблема в том, что я хочу создать столько объектов ClassOne (PixelSlider), сколько мне нужно. Я хочу передать им объект String, который сообщает им, какую переменную-член ClassTwo (AudioProcessor) нужно изменить. Логически это можно было бы сделать, передав ссылку на объект String с тем же строковым значением, что и имя переменной-члена ClassTwo. Как это,...

ClassOne::ClassOne (ClassTwo& two, String& string)
        : classTwoReference (two), stringReference (string)
    {
        two.(string) = 3;
    }

Это не работает в JUCE, но может ли кто-нибудь сказать мне, как это сделать без необходимости создавать кучу разных классов, почти таких же, как ClassOne (PixelSlider), которые изменяют разные переменные-члены ClassTwo (AudioProcessor)?


person Stevey Yarusinsky    schedule 17.01.2015    source источник
comment
Очевидно, что это не работает в JUCE В этом нет ничего очевидного. Также обратите внимание, что вы должны отредактировать и улучшить свой последний вопрос, а не публиковать еще один.   -  person πάντα ῥεῖ    schedule 17.01.2015
comment
Так вы говорите, что это должно работать? Кроме того, я удалил свой последний вопрос. Его улучшение означало бы его полное изменение, поэтому я просто опубликовал новый и удалил его.   -  person Stevey Yarusinsky    schedule 17.01.2015
comment
Я сказал, что для меня нет ничего очевидного, почему этого не должно быть. Если это не работает для вас, вы должны уточнить, что именно не работает.   -  person πάντα ῥεῖ    schedule 17.01.2015
comment
способ сделать это - создать разные классы, такие как ClassOne, которые изменяют разные переменные. Если это не так, вам нужно сохранить некоторую индексацию для членов класса и передать индекс переменной, которую вы хотите изменить (хотя это выглядит очень уродливо)   -  person Pankaj Bansal    schedule 17.01.2015
comment
Спасибо Панкай! Это была моя интуиция, но я надеялся, что есть более простой способ сделать это. Кстати, очевидную часть я отредактировал, так как даже не могу толком объяснить, почему она не работает.   -  person Stevey Yarusinsky    schedule 17.01.2015
comment
Или вы можете сделать некоторое сопоставление строки с переменной в ClassTwo, например map[someString] = two.someVariable. Затем передайте строку и измените ее. опять некрасиво звучит..   -  person Pankaj Bansal    schedule 17.01.2015
comment
@SteveyYarusinsky Вы все еще не объяснили, что не работает.   -  person πάντα ῥεῖ    schedule 17.01.2015
comment
@πάνταῥεῖ это не сработает. Как вы измените переменную two на строку. two.string = 3 не имеет никакого смысла, я чувствую, что переменная не является строкой   -  person Pankaj Bansal    schedule 17.01.2015
comment
Да, я думаю, мне просто нужно сделать несколько производных классов на основе ClassTwo. Я предпочитаю, чтобы это не было уродливым. И @πάνταῥεῖ, что не работает, так это то, что two.(string) = 3; дает мне ошибки компиляции.   -  person Stevey Yarusinsky    schedule 17.01.2015
comment
Существуют языки (например, PHP), в которых вы можете использовать переменную для ссылки на другую переменную, например. $x = 1; $s = 'x'; $$s = 42; установит $x на 42. Термин для этого — отражение. Если вы будете искать отражение в C++, вы найдете МНОГО вопросов по этому поводу. Короткий ответ заключается в том, что в C и C++ этого нет, компилятор никак не может преобразовать строку, сгенерированную во время выполнения, в поле-член. Язык просто предназначен для этого. Есть много разных способов добиться чего-то подобного, но не ТОЧНО этого.   -  person Mats Petersson    schedule 17.01.2015
comment
Я попытаюсь объяснить это снова, когда я создаю экземпляр ClassOne (PixelSlider) в своем классе графического интерфейса, я передаю ему ссылку на объект classTwo (AudioProcessor) и ссылку на строковый объект. Например, слайдер PixelSliderOne (аудиопроцессор&p, String&memberOfAudioProcessorThatIWantToModify); В методе объекта PixelSlider я хочу, чтобы член AudioProcessor был изменен, но я хочу указать, какой из них я хочу изменить при создании объекта PixelSlider, чтобы мне не приходилось создавать кучу классов только с несколько строк кода, который отличается. Имеет ли это смысл?   -  person Stevey Yarusinsky    schedule 17.01.2015
comment
@MatsPetersson, спасибо! Я подумал, что может быть так. Хотя это позор. Я думаю, что лучшим решением было бы создать классы, которые наследуют функции ClassOne, а затем переопределить те, которые содержат код, который я хочу изменить. Будет ли это хорошим маршрутом?   -  person Stevey Yarusinsky    schedule 17.01.2015
comment
Есть много решений, это действительно зависит от общей ситуации. Ваш пример слишком прост/мал, чтобы ясно видеть, что вы пытаетесь сделать. Опубликованный ответ является ОДНИМ из них, но не всегда правильным ответом.   -  person Mats Petersson    schedule 17.01.2015
comment
Старайтесь избегать using namespace std; вот почему: stackoverflow.com/questions/1452721/   -  person ilgaar    schedule 17.01.2015
comment
А, понятно, хотя я не использую никаких пространств имен в своем коде JUCE. Спасибо за совет @igaar очень полезно!   -  person Stevey Yarusinsky    schedule 17.01.2015


Ответы (1)


Если я правильно понимаю, вы пытаетесь привязать цель PixelSlider к члену AudioProcessor во время выполнения, что, как вы обнаружили, не может быть сделано так, как вы предлагаете ( two.(string) = 3 ). Одним из способов достижения этой привязки может быть использование шаблона команды (http://sourcemaking.com/design_patterns/command/cpp/2).

AudioProcessor может предоставить набор этих командных объектов для каждого изменяемого свойства...

AudioProcessorCommand
AudioProcessor::GetCommandByName(String const& properyName) const
{
   ...
}

... который вы можете передать конструктору PixelSlider. Что-то в духе...

PixelSlider::PixelSlider(AudioProcessorCommand& command)
: command_{command}
{
  ...
}

Когда значение PixelSlider изменится, вы вызовете команду ...

command_(this->value_);
person gmbeard    schedule 17.01.2015
comment
Это именно то, что я искал! Вы, сэр, гениальны. Спасибо! - person Stevey Yarusinsky; 17.01.2015
comment
@gmbeard this.value_ неверно, лучше вообще не указывать this->value_ или this. - person πάντα ῥεῖ; 17.01.2015
comment
@πάνταῥεῖ Аргх! В последнее время я много пишу на C#. Хорошо подмечено - person gmbeard; 17.01.2015