В данный момент я изучаю C++ (начинающий). Мне нужен метод для изменения нескольких переменных за его пределами, которые, если я правильно понимаю, не будут/не смогут измениться за пределами этой функции, если не будет указан и возвращен определенный тип. Я также знаю, что не могу возвращать из функции несколько типов.
struct multiTypes {
int i = 0;
float f = 1.0;
std::string a = "testing";
};
multiTypes test() {
multiTypes mT;
mT.i += 2;
return mT;
}
int main() {
std::cout << test().i << '\n';
std::cout << test().f << '\n';
std::cout << test().a << '\n';
}
Хотя это работает, мне было интересно, какие еще существуют альтернативы для достижения того же результата?
Мы сможем дать более точные ответы, если вы уточните реальную проблему, которую пытаетесь решить. Вы можете изменять переменные из функции с помощью ссылочных переменных, вы можете использовать шаблоны для создания собственного типа возвращаемого значения и т. д. Но, в зависимости от вашего варианта использования, могут быть лучшие/более простые решения.
«есть ли альтернативное или лучшее (традиционное или даже производительное) решение?...» В чем проблема с текущим кодом? Также вы уверены, что не занимаетесь микрооптимизацией?
Как и многие другие вещи в программировании, это зависит от ситуации. В реальном сценарии использования вам следует профилировать и протестировать сборку выпуска, чтобы найти одно или два основных узких места и сосредоточить на них свои усилия по оптимизации.
Как правило, struct
практически никогда не следует использовать в C++. Прежде чем приступить к изучению C++, вы должны уже знать об объектно-ориентированном проектировании и классах. Если вы этого не сделаете, есть гораздо более простые языки, которые лучше использовать при изучении самого объектно-ориентированного программирования.
@user12002570 user12002570 Нет проблем. Как я уже сказал, я сейчас учусь и вообще мне интересно.
вы бы не вызывали функцию каждый раз, когда хотите получить доступ к члену структуры, а скорее вызывали бы multiType x = test();
, но в остальном в вашем подходе нет ничего плохого
@Лундин, это ужасное практическое правило. Структура ОП совершенно кромулентна. C++ — многопарадигмальный язык.
Примечание: ничто в этом коде не требует дополнительных вещей, которые делает std::endl
. Используйте '\n'
, чтобы завершить строку, если у вас нет веской причины не делать этого.
@463035818_is_not_an_ai или auto [x, y, z] = test();
@Caleth Если вы не используете объектно-ориентированный дизайн, вы делаете это неправильно. Новичкам бесполезно сначала научиться делать что-то неправильно, а потом от всего этого отучиться. Класс со всеми открытыми членами почти всегда является неправильным дизайном. И это важно для этого вопроса, потому что вместо этого, вероятно, следует сделать std::cout << test << std::endl;
или, возможно, test.str()
или что-то подобное.
@Лундин multiTypes
— отличный специалист по безопасности. У него нет инвариантов, которые нужно поддерживать.
Какой лучший способ научить новичка использовать пользовательскую структуру данных, основан на мнениях. кед. Голосование за закрытие
@Caleth Также не существует такого понятия, как «мультипарадигмальный» язык, по той же причине, что и не существует такого понятия, как «объектно-ориентированный язык». Есть языки с поддержкой объектно-ориентированного программирования, а есть языки без нее. Есть правильно спроектированные программы, а есть плохие. Независимо от языка, нет оправдания тому, чтобы практиковать плохой дизайн или внушать новичкам, как делать плохой дизайн. Просто посмотрите на весь ущерб, нанесенный злой книгой K&R - она учит синтаксису и функциям в основном хорошо, но преподаваемый стиль кодирования должен был быть объявлен преступным.
@463035818_is_not_an_ai Спасибо, это было просто для тестирования.
@user12002570 user12002570 Что для тебя не имеет смысла? Возможно, я смогу уточнить.
Использование структуры вполне нормально
@Лундин, тебе не обязательно писать в объектно-ориентированном стиле на C++. Вы можете писать в функциональном или процедурном стиле. ОО — неправильный способ написания всего программного обеспечения.
@Austin В настоящее время сосредоточен на различных способах структурирования программы и доступа к различным областям/наследованию/полиморфизму. Так что никакой острой актуальной проблемы как таковой нет.
@Lundin В чем проблема, начиная с C++, если я знаю, что хочу его использовать? Я могу правильно выучить его с нуля, и мне не нужно сначала тратить больше времени на изучение другого языка, чтобы достичь желаемого результата (знание того, как писать код на C++). Я работаю в другой сфере, это побочное дело
@stackaccount — Добро пожаловать в C++. Не существует более великого сообщества, в котором мы все были бы полностью согласны с какой-то лучшей практикой для всего. Вместо этого язык используется для множества разных вещей в отдельных сообществах с разными правилами. IMO, возвращение структуры с открытыми членами вполне нормально, если это единственное использование этой структуры. В противном случае вам было бы лучше использовать класс, управляющий частными членами. ЮММВ.
@Caleth Частная инкапсуляция + автономные объекты/модули — правильный способ написания всего программного обеспечения. И это 2 из 3 столпов объектно-ориентированного подхода, причем наследование является третьим, и его просто «приятно иметь». Имейте в виду, что я программирую практически исключительно на C, но это не мешает мне писать правильно спроектированные программы. «Функциональный стиль» — это просто причудливое название для «крыльев», или, если хотите, «не разрабатывать программы» — его на самом деле не существует.
@stackaccount Дело в том, что объектно-ориентированный дизайн - это концепция проектирования программ, не зависящая от языка, которую полезно знать прежде всего. C++ очень сложен, даже если вы заранее знаете ОО. Даже для того, кто, скажем так, является опытным Java-программистом, но никогда не программировал на C++, будут странные и экзотические сюрпризы. Вы можете изучить объектно-ориентированный подход, изучая C++ (это то, что я когда-то делал), но я не рекомендую это делать.
Это быстро отвлекает. Обсуждение объектно-ориентированного подхода и других парадигм лучше всего подходит для обсуждения в чате, а не для комментариев по этому вопросу. Конечно, поскольку вопрос по своей сути основан на мнениях, это естественное развитие событий, но лучшее действие в этом случае — проголосовать за закрытие вопроса.
@Lundin, комитет C++ не согласился с вами еще в 2020 году
@Lundin Разве ООП не приводит к увеличению длины программ и, следовательно, к увеличению времени выполнения? Я не рекламирую это, просто я что-то прочитал. Не имея опыта, прямо сейчас я думаю, что в целом мне хотелось бы писать так, чтобы А) было чисто (просто в обслуживании и развитии), Б) работало по назначению и без проблем, и В) было ориентировано на производительность. Мне нравится, чтобы программы были быстрыми. Поэтому, учитывая это, я бы выбрал то, что решает любую проблему, с которой я сталкиваюсь, наилучшим из известных мне способов. Отсюда мой первоначальный вопрос.
@Caleth Тот факт, что вы можете писать «функторы» и тому подобное с помощью struct, не означает, что вам это нужно. То, что когда-то называлось STL, использует структуру по традиции, а не по каким-то причинам. Большинству вещей в C++ не хватает обоснования того, почему они существуют на самом деле.
@ Крис, позволь мне отредактировать вопрос.
Если вопрос закрыт, пожалуйста, отредактируйте его. Закрытые вопросы можно открыть повторно, если они сочтены соответствующими правилам переполнения стека. Как спросить
@stackaccount Нет, объектно-ориентированный подход — это способ разработки программ, он очень мало влияет на производительность. Точно так же C++ в большинстве случаев не обязательно медленнее C.
@Lundin std::in_out_out_result
— это структура с тремя общедоступными элементами данных (и преобразованиями), которая существует для присвоения осмысленных имен трем значениям, которые все хотят вернуть из одной функции. ОП именно об этом и спрашивает
@ Крис, я изменил его на более общий вопрос, не основанный на мнениях.
Итог: C++ предоставляет практически безграничные возможности для написания плохих программ. Но это не значит, что нам следует это делать. Аналогично, то, что функция существует в C++, не означает, что мы должны ее использовать. Понимание этого является ключом к написанию удобных в сопровождении программ на C++. В противном случае через год вы будете сидеть в каком-то аду метапрограммирования шаблонов, размышляя о том, как реализовать Z в вашей проблеме XYZ, вместо того, чтобы разрабатывать приложение A, над которым, по мнению вашего босса, вы работаете.
@Lundin Является ли ваша проблема с использованием структур тем фактом, что они по умолчанию общедоступны? Похоже, большинство с вами не согласны. Все, что я знаю, это то, что в учебных пособиях они используются. PS: Я сам себе начальник, в другой сфере, кроме сути.
Еще не упомянуто: std::variant может справиться с некоторыми головными болями за вас. Возвращаемые значения могут быть совершенно несвязанными типами. По крайней мере, для изучения современного C++ это весьма полезно знать. Однако я бы никого не винил за выбор более простого способа, как показано в вопросе.
@stackaccount Да, в этом и проблема — в остальном они на 100% эквивалентны class
, поэтому нет причин, по которым вам не следует всегда использовать class
. И я не знаю, смеяться мне или плакать по этому поводу. Вот я, в основном программист на C, который избегает C++, когда это возможно, - читаю лекцию будущим программистам C++ использовать объектно-ориентированный дизайн, который, очевидно, сбивает их с толку. Печальное положение дел.
@Lundin Ха, такова жизнь. Если вас это утешит, структура, с которой я на самом деле возюсь, находится внутри класса;)
@Питер Пойнтер, мне неловко признаться, я попробовал std::variant
и по какой-то причине не получилось.
@stackaccount О, я уверен, что вы сможете найти для него хороший учебник (поиск варианта учебника по C++ должен найти его для вас). Я просто не буду ссылаться на него, поскольку однажды он может устареть или перестать существовать.
Да, вполне нормально определить тип для хранения нескольких возвращаемых значений для определенной функции.
Взгляните на std::in_in_out_result , он по сути такой же, как ваш тип, и используется рядом функций в стандартной библиотеке.
Вы должны дать типу и его членам значимые имена, но нет никакого контекста относительно того, какими они будут в минимальном примере в вашем вопросе.
Какие еще альтернативы существуют для достижения того же результата?
Если у вас есть значимые имена, это предпочтительнее, чем возврат test
std::tuple<int, float, std::string>
, который является еще одним типом, который может хранить эти три значения.
std::tuple<int, float, std::string> acceptable_test() {
return { 2, 1.0, "testing" };
}
Любой из этих вариантов лучше, чем test
принимать ссылочные параметры для этих значений, поскольку на сайтах вызовов не очевидно, что все значения перезаписываются.
void bad_test(int& i, float& f, std::string& a) {
i = 2;
f = 1.0;
a = "testing";
}
Также может быть полезно перегрузить <<
для этого типа, чтобы можно было печатать std::cout << mT << '\n'
.
@ Крис, это зависит. Бывают ситуации, когда auto [x, y, z] = test(); std::cout << x << y << z << '\n';
более понятен
Спасибо, @Калет! Обычно я использую осмысленные имена. Иначе я бы заблудился. Также я не знал, что это std::tuple<int, float, std::string>
может содержать несколько типов, спасибо :)
«Мне нравится выполнять несколько операций в методе и изменять несколько переменных за его пределами, которые, если я правильно понимаю, не будут/не смогут измениться вне области действия этой функции, если только не будет указан и возвращен определенный тип.. ..» Это не имеет смысла, по моему мнению.