0

Не могу понять, как перебрать все радиобаттоны в GroupBox. Попробовал сделать в C#-стайл:

for each (Control c in Age_GBox.Controls)
{
    MessageBox::Show(c.ToString());
}

Ругается на то, что .Controls возвращает System::Object^. Ок, поменял тип. Сделал так:

for each (System::Object ^ c in Age_GBox.Controls)
{
    MessageBox::Show(c.ToString());
}

Заработало, тип элементов выводит. Попытался на радостях получить доступ к свойству Checked да и вообще любому другом свойству. Не выходит, этот объект вообще не имеет никаких свойств, кроме стандартных вроде Clear, Add, ToString и пр. Что не так?

αλεχολυτ
  • 28,987
  • 13
  • 60
  • 119
ComeInRage
  • 1,601
  • 6
  • 14
  • В for each укажите Control^ - знак ^ обязателен в данном контексте. – Alexander Petrov Mar 17 '21 at 10:09
  • Вы сперва поставили метку C++. (Устало, в сотый раз) C++ и C++/CLI - это разные языки! То, что у них совпадают первые символы, значит не больше, чем совпадающие первые символы в языках Java и JavaScript, или python и pascal. Если вы учите именно C++, то не трогайте C++/CLI. И, соответственно, забудьте про WinForms, потому что этот GUI-фреймворк под платформу .NET. – Alexander Petrov Mar 17 '21 at 10:13
  • Я бы с удовольствием забыл про C++/CLI, но (Устало, в сотый раз), наши устаревшие университеты, которые все еще даже используют C++98 стандарт требуют от меня лабораторные по C++/CLI и WinForms. Я бы с удовольствием перешел в C# для этих целей, но отчисляться из-за невыполнения лабораторных мне не хочется. – ComeInRage Mar 17 '21 at 10:15
  • 1
    Visual Studio - хорошая IDE. Но я всегда говорил и буду говорить, что для изучения C++ лучше взять другую IDE. Потому что VS позволяет писать на многих языках, в том числе C++/CLI. Вот начинающие и путаются. После знакомства с консольными программками, хочется попробовать ГУЙ, вот и натыкаются рано или поздно на WinForms, а это совсем другая платформа! В итоге учат то, что никогда не пригодится. – Alexander Petrov Mar 17 '21 at 10:16
  • Тогда не ставьте метку C++! Даже не упоминайте этот язык в контексте WinForms! – Alexander Petrov Mar 17 '21 at 10:17
  • Увы, но я еще с первого курса понял, что тут меня ничему не научат. Но, чтобы не вылететь из университета или со стипендии, приходится как раз таки учить эти ненужные знания. – ComeInRage Mar 17 '21 at 10:22

1 Answers1

1

Очевидно, что если при итерации используется объект базового класса System::Object, то и методы у него будут доступны только этого класса. Если нужно вызвать метод какого-то производного класса, то сначала нужно убедиться, что объект реально соответствует этому классу, и уже после вызвать нужный метод. Делается это путём приведения типов. См. operator dynamic_cast:

RadioButton^ rb = dynamic_cast<RadioButton^>(c);
if (rb != nullptr) { 
   bool checked = rb->Checked(); 
}
αλεχολυτ
  • 28,987
  • 13
  • 60
  • 119
  • Попробовал, но не выходит. Компилятор ругается на то, что нельзя использовать указатели на элементы C++/cli. Или я неправильно его использую?

    RadioButton* c = dynamic_cast <RadioButton*> (c);

    – ComeInRage Mar 17 '21 at 09:33
  • 1
    @CSharpLooser указатели управляемые должны быть (с шапочкой ^). По ссылке есть пример: dynamic_cast<String^>(o). Добавил в ответ пример кода. – αλεχολυτ Mar 17 '21 at 09:34
  • Увы, но ваш пример не работает. Выдает исключение: System.NullReferenceException: "Ссылка на объект не указывает на экземпляр объекта." Вот такой код: RadioButton^ rb = dynamic_cast<RadioButton^>(c); bool checked = rb->Checked; MessageBox::Show(checked.ToString()); Ругается на строку, где мы вызываем свойство Checked – ComeInRage Mar 17 '21 at 10:11
  • @CSharpLooser так надо проверку rb на nullptr добавить после каста. Ведь на форме могут и другие контролы быть помимо радиокнопки. По NullReferenceException читайте тут. – αλεχολυτ Mar 17 '21 at 10:14
  • Для теста я специально оставил только Радиобаттоны. Если проверять на nullptr, то ни разу не вызывается все, что под условием. То есть rb Всегда nullptr – ComeInRage Mar 17 '21 at 10:16
  • 1
    @CSharpLooser если dynamic_cast вернул null, значит тип не тот. Надо проверить что там вообще за типы перебираются, например, через какой-нибудь с->GetType()->ToString() или нечто подобное. – αλεχολυτ Mar 17 '21 at 10:20