| Версия для печати темы
Нажмите сюда для просмотра этой темы в оригинальном формате |
| Форум программистов > C/C++: Общие вопросы > Реализация С# - конструкции в С++ |
| Автор: ioManip 12.11.2014, 13:01 | ||||
Привет. Есть такой вот кусок кода
И к примеру его применение
А как будет выглядеть, такая же реализация на С++ ? Мне просто не совсем понятно, Value - это как метод? а set get ? |
| Автор: Guinness 12.11.2014, 13:25 | ||||
Как таковых свойств в языке нет. Можно, например, использовать функции и возвращать из них ссылку или указатель.
Можно просто объявить Value как public переменную класса:
Но это рабочие случаи только если get и set - public. Полного аналога в языке нет. Можно придумать свой класс property, который будет выполнять похожую функциональность. Думаю в интернете должны были найтись умельцы, попытавшиеся реализовать подобное. |
| Автор: Ihost 12.11.2014, 13:44 |
| Отчего же? Если речь идет о языке C++, то возможность реализовать свойтсва с getter/setter-ами вполне себе существует, и основана на форсированном преобразовании типа в нестатическом перегруженном операторе присваивания http://www.codeguru.com/cpp/cpp/cpp_mfc/article.php/c4031/Implementing-a-Property-in-C.htm Если речь идет о VC++, то там есть более элегантное решение - констуркция __declspec property |
| Автор: Ihost 12.11.2014, 14:02 | ||
Да говорили и возможно подразумевали это, но в конкретном Вашем примере предполагался простой класс с двумя функциями для получения и записи свойства - в то время как в примере по ссылке *нет* необходимости вызывать какие-то функции, и со свойством можно работать именно как с публичной переменной, в стиле C#
Учитывая что метод getter/setter-а вызывается полностью автоматически, и внешне такое свойство мало отличимо от настоящего, то в принципе можно сказать, что реализация свойств в языке C++ есть, хотя и не прямая конечно |
| Автор: ioManip 12.11.2014, 14:39 | ||||||
Поправьте, если не так. То есть при такой записи
и таком применении
Я буду получать значения, которые записаны в индексах i и j ? |
| Автор: Guinness 12.11.2014, 15:07 |
Нет, Вам нужно добавить скобочки, чтобы работало. Чтобы было так, как Вы хотите, либо используйте предложенные варианты Ihost`ом, либо public переменная. Ещё можно, конечно, использовать managed C++, но, имхо, лучше не стоит. |
| Автор: ioManip 12.11.2014, 15:12 |
| Хорошо, спасибо! |
| Автор: Lukkoye 12.11.2014, 21:55 | ||||
Если не обращать внимания, что нативной поддержки не существует. А любые велосипеды - весьма весьма ограниченные костыли. Без нативной поддержки приходится в ручную писать дополнительный код. И Код усложняется. Заметьте - на ровном месте. Кроме того, костыльные велосипеды не способны покрыть всю возможную область применения, и охватывают лишь частные случаи: Пример из указанной выше ссылки:
Возвращает по значению, и только для неконстантных объектов. Попытка сделать универсально провалится. Объяснять почему сейчас не стану - кто пробовал, тот знает. Там вылезет 100500 всевозможных нюансов в самых разных случаях. Сложность конструкции будет только расти. И не избавит пользователя от необходимости писать дополнительный код: в ручную чего то там поднастраивать. В этой ситуации проще написать простой и понятный даже новичку геттер/сеттер. Чем геммороится с шаблонами, которые не избавят от необходимости в ручную писать код, а только все усложнят. Собственно, поэтому и не прижились проперти на плюсах. Игра не стоит свеч. |
| Автор: Ihost 13.11.2014, 14:12 | ||||
Так это же пример самой простой реализации, если нужен возврат по ссылке - пожалуйста, можно сделать такие исправления
Прекрасно используется следующим образом, в первом случае значение копируется надлежащим образом, а во втором - получается по ссылке; для запрета получения объекта по ссылке getter-функция может форсированно создавать копию объекта:
Если использовать диалект C++11, то можно еще больше усовершенствовать код с помощью конструкция перемещения для неконстантных rvalue-ссылок В общем непонятно, в чем вообще заключается Ваша позиция? Если уж на то дело пошло, getter-ов и setter-ов нет вообще ни в каком языке - в конечном счете они превращаются в нативный или байт-код в зависимости от целевой используемой технологии В языке C# эти элементы- считайте обертки для обычных функций, и все, и более того в C# не удастся передать такую штуку по ссылке, ибо ref/out доступны только в функциях Так что реализация в C++ даже более мощная, чем натуралтная поддержка в некоторых другиях языках Вам не нравится отсутствие синтаксического сахарка? Это уже философский вопрос или вопрос терминологий, но говоря Вашими словами, игра не только стоит свеч, но и вполне упрощает код В этом и есть философия C++- несмотря на всю сложность языка, за счет определенных конструкций управления функциональным потоком из инициируемых объектов первого рода, получает гибкость и удобство |
| Автор: xvr 13.11.2014, 14:43 | ||||
Попробуйте сделать так -
|
| Автор: Ihost 13.11.2014, 15:24 | ||||||
Если учитывать что printf- это не совсем типичная для языка C++-функция, ибо она принимает нетипизированные аргументы, то действительно есть небольшие аспекты, решаемые передачей строгого типа Конструкция printf("%d",test); вообще работает только потому, что разрешен тривиальный копирующий конструктор- немного модифицировать класс, чтобы он перестал быть POD-типом error: cannot pass objects of non-trivially-copyable type 'class PropTest' through '...' printf("%d \n", test); Если выводить даше шаблонными функциями, проблемы не возникает
|
| Автор: xvr 13.11.2014, 16:39 | ||||||
Ну есть еще несколько конструкций, где будут проблемы. Ну например абсолютно С++ конструкция -
Ошибка при компиляции:
|
| Автор: Lukkoye 13.11.2014, 20:45 | ||||
А потом ещё и ещё исправлений! Нужно больше исправлений, что бы выкрутиться из всех возможных ситуаций: Это - только верхушка айсберга.
Дальше хуже - великое множество ситуаций на шаблонах. Проперти на плюсах не дают никаких преимуществ, абсолютно ничего не привносят такого, чего нельзя было бы сделать при помощи простых и всем понятных сеттеров/геттеров. А сложность (в первую очередь пользовательского кода, про инструментальный я вообще молчу, там термоядерная магия на шаблонах все равно не справится со всеми случаями) - увеличивают неимоверно. Что делает их существование на этом языке бессмысленным. |
| Автор: Ihost 14.11.2014, 14:06 | ||
| Эн нет- классическое свойства вида property работают только с элементами, передаваемыми по значению, и никаких ссылок и константных элементов они не подразумевают В самом деле в том же C# вы можете передать и получить только значение!!! Да это может быть ссылочная переменная, указывающая на экземпляр класса или массива, но саму эту переменную получить по ссылке невозможно - для свойств не предусмотрен ref или out, так что непонятно о чем вообще речь Можно сказать что в C++ property-свойства даже мощнее и функциональнее, так как можно реализовать их и с учетом ссылок, и константных объектов - шаблоны все это позволяют Так что мой тезис в том, что свойства на C++ удобны, функциональны и удобны для применения, в то время как именованные функции GetX/SetX создают огромные неудобства и в клиентском, и библиотечном коде, и их использование при существовании нормальных свойств - бессмысленно Да есть небольшие тонкости с дедукцией типов в шаблоне, но путем добавления еще одного аргумента можно получить, что нужно Вообще язык шаблонов C++ является Тьюринг-полным, так что сделать в нем мануальную дедукцию типов и генерацию целевого шаблона не составит слишком большого труда И напоследок пример, демонстрирующий неотличимое использование property-свойства для сложных подлежащих типов
Да это немного разбухтится, если использовать фундаментальный тип, но сделать всего лишь два шаблона для фундаментальных и наследуемых типов- дело очень простое; более того если несколько усложить развертывание шаблона, такое определение можно сделать автоматическим **Единственная** сложность заключается только с функциями printf/scanf, или обобщенными вариадическими функциями в C-стиле, но если уж делать код в C-стиле, о каких подобных функциях можно вообще говорить - или делать нормальные вариадические шаблоны вокруг них, или ничего Напоминаю что вариадические функции в C-стиле **воообще** ничего не знают о своих аргументах, и то что property не работают с ними автоматически, это проблемы не proprty, а отсутствия типизации в них Обсуждение зашло довольно в сложную ситуацию, и причиной тому по всей видимости является разница в *логическом* и *техническом* понимании определенных элементов языка программирования Допустим есть языки A и B, первый из которых поддерживает полноценное *синтаксическое* ООП с классами, наследованием и всеми необходимыми элементами, а второй - нет, но может вполне реализовать его с помощью синтаксического сахара Есть программа на языке A, включающая один класс со статической функцией, и реализацию всей логики в ней; в программе на языке B с помощью синтаксического сахара определяюстся объекты и классы, есть четкая архитектура инкапсуляции и наследования Какую из программ Вы считаете объектно-ориентированной? Мое мнение указывает, что только программа на языке B, поскольку в расчет берется не ситнактические, а архитектурные особенности! Ваше мнение видимо будет диаметрально противоположным, поэтому дальнейшая дискуссия бессмысленна |
| Автор: xvr 14.11.2014, 17:02 | ||
Отнюдь Программа В конечно, но тут речь шла не об этом. А речь шла о том, что на С++ невозможно реализовать проперти, использование которых синтаксически не отличается от использования полей классов/структур (или хотя бы просто переменных). Можно реализовать проперти, которые почти не отличаются, но полную замену получить нельзя (даже если не принимать во внимание код, который попытается получить указатель или ссылку на проперть) |
| Автор: Lukkoye 14.11.2014, 20:50 | ||
Какие именно "огромные неудобства" ? Писать приходится меньше. Код проще. Приведенный вами код не рассматриваю, Когда вот такие ошибки лезут: source_file.cpp:5:30: error: ‘Property<T>::Property() [with T = std::basic_string<char>]’ is private class Property : public T { Property() { } Мне уже не хочется всерьёз рассматривать пример. |
| Автор: Ihost 19.11.2014, 12:49 | ||||||
| Да тема вышла действительно очень интересной, хотя по-прежнему совершенно непонятно, откуда стереотипные возражения против prorerty-свойтсв на языке C++ - да синтаксические средства языка значительно более выразительные, но это не повод отказываться от удобных getter/setter Окей допустим определен UI-объект по аналогии как в .NET, в котором значительное число параметров с иерархической вложенностью; в таком случае есть два потенциальных варианта записи (Все имена классов- вымышленные, но поясняющие суть аналогии)
По мне такой вариант адекватен только на языке Java, где это сделано специально ради колоссального упрощения синтаксических структур языка, такой как невозможность перегрузки операторов и переопределения преобразования типов
Можно вообще не использовать ни свойства, ни классы, а разрабатывать к примеру на языке ассемблера! Теперь давайте перейдем к совместимости: - Абсолютная 100% поддержка для Visual C++ и Borland C++ посредством конструкций __declspec и __property соответственно - Достаточно интересная поддержка для C++11 и старше посредством кода следующего образца http://duriansoftware.com/joe/Self-aware-struct-like-types-in-C++11.html , в том числе для шаблонных функций, ссылок и константных выражений - 100% поддержка для набора инструментов вида Qt - Достаточная для удобной работы поддержка по образцу C++-кода, приведенного несколько сообщений назад При копировании на форум в том сообщении изчез спецификатор public, и если его вернуть, все заработает надлежащим образом; при добавлении определенной металогики подобную схему можно использовать и для фундаментальных типов, и для обычных классов - сейчас надо мануально указывать класс подлежащего типа Как итог можно сказать, что в C++ действительно нет property-свойств; впрочем с таким же успехом там не и методов классов, и даже переменных - при компиляции это невозможно вернуть обрано, в отличие от того же C#, который может полностью быть подвергнут обратной разработке Более того надо помнить, что C++ - язык достаточно низкоуровневый! Никто ведь не требует от той же функции printf, чтобы она сама определяла тип аргументов и их число - все знают что это невозможно, и подставляют мануальные аргументы С prorerty-свойствами ситуация несколько похожая- в случае их простой реализации, в некоторых достаточно сложных конструкциях потребуется операция explicit-приведения типов - но это ничуть не умаляет их удобства по сравнению с неудобными и громоздкими вызовами GetX/SetX Если кого-то не убедило и это, то можно вспомнить про вполне легальную синтаксически, но могущей привести к последующими проблемам времени исполнения конструкции
Присваиваемые левосторонние значения от функций, которые являются локальными переменными - не лучшая черта языка, но она есть Property-свойства же работают удобно и изяшно и не обладают почти никакими недостатками в общей атмосфере C++-кода |
| Автор: NoviceF 20.11.2014, 18:14 | ||||||
Так если в приведённом стиле изобразить первый вариант, он получится не на много более грамоздким:
|
| Автор: Dem_max 20.11.2014, 19:24 | ||
Примерно так и будет выглядеть
|
| Автор: Ihost 20.11.2014, 23:44 | ||||
Хорошее решение, правда разве что
В одну строчку вряд ли получится записать, а если и получится - getter-ы будут вызываться дважды, и если в них осуществляется выполнение реальной функциональной нагрузки, то производительность снизится в 2 раза, в то время как в реальных property-элементах такого не возникнет |
| Автор: Lukkoye 20.11.2014, 23:49 | ||||
Во-первых первый вариант не эквивалентен второму по логике работы. Потому что в первом варианте все промежуточные значения реализованы по значению. А значит hue += 10; увеличит внешнию копию, в то время, как во втором случае +=10 увеличит переменную-член класса. А во-вторых:
Таким образом, с точки зрения количества буковок, по факту первый вариант длиннее второго только на () и точечку. А теперь возвращаясь к нашим баранам. Если писать просто и не городить огороды с дураццкими промертями, то код будет не просто проще. Его будет меньше: 1. код классов проще. И по сложности кода и по количеству. потому что: 1.1 Вариант, когда вам не нужны сеттеры/геттеры, и вы делаете член public. Получаете точно такой же синтаксис, какой предоставляют проперти. Максимальную эффективноть и никакого геммороя (до тех пор, пока не понадобятся сеттеры/геттеры. Практика показывает - проблем не возникает). 1.2 Вариант, когда вам нужны сеттеры/геттеры, потому что нужно не просто предоставить доступ к данным, но и выполнить какую то дополнительную логику. Например, выполнить логгирование, или произвести валидацию, или испустить сигнал... В этом случае вам в любом случае понадобится функция-сеттер (ну или геттер). Только в простом случае вы пишите сеттер и больше ничего. В случае с проперти, пишите проперти, пишите сеттер, и потом навешиваете его на проперти. Тройная работа. Практического смысла в проперти нет никакого. С тем же успехом можно было бы просто реализовать сеттер. 2. на пользовательской стороне в наши дни уже давно никто не пишет полные имена методов или переменных. достаточно вбить первые две буквы, и ИДЕ подскажет полное имя. И в этом смысле совершенно не принципиально, что вбивать: имя переменной, или имя метода. Все равно используется автодополнение от ИДЕ. Поэтому с точки зрения использования ни public-переменные, ни простые сеттеры, ни проперти не имеют никакого выигрыша друг перед другом в плане скорости разработки. ----------------------------------------------------------------------------------------------------------- Ваш вариант ни разу не адекватный. Напротив - он бессмысленный, потому что не дает никакого профита, а только зазря усложняет код: Он не решает никаких проблем, с которыми не могли бы справиться обычные сеттеры. Он вообще не привносит ничего принципиального нового - это лишь бесполезный сахар, потому что с точки зрения функциональности он не привносит ровным счетом ничего такого, чего нельзя было бы реализовать с помощью обычного сеттера. Не ускоряет, а только замедляет разработку за счет увеличения времени на конструирования в классах-владельцев более сложный кода. Требует понимания и навыков работы с шаблонами. Шаблоны в бизнес-коде без какой бы то необходимости приводит к удорожанию разработки за счет более высокого порога вхождения разработчиков. ------------------------------------------------------------------------------------------------------------- Резюмируя: без всякой необходимости, совершенно напрасно усложнять себе жизнь? Это глупость. Техника оказалась не востребованной на плюсах, именно потому что бессмысленная. |
| Автор: NoviceF 21.11.2014, 09:54 |
| [deleted] Выше написано правильнее Я посчитал, что геттер возвращает по значению, но если по ссылке, то можно, конечно, сделать короче. |
| Автор: Ihost 21.11.2014, 10:54 | ||||
Если сахар совсем не по душе, можно разрабатывать программы на чистом C или ассемблере - в первом случае минимум сахара + какая-никакая переносимость; кому-то может нравиться белый сахар, кому-то коричневый тростниковый - о вкусах вообще довольно бессмысленно спорить
Можно рассмотреть несколько аспектов: - Для обеспечения гибкости достаточно низкоуровневого C++ в нем был придуман синтаксических сахар в виде перегрузки операторов и implicit-конструкторов, благодаря которым те же вектора можно складывать по знаку плюс, или использовать красивые комплексные числа Если Вам все это не нравится, всегда можно использовать "не-сахарную" версию, но зачем, если можно сделать красивее и изящнее - Если в Вашей программе есть многочисленные формуло-подобные расчеты со множеством переменных классов, то код без property-свойств выглядит абсолютно нечитаемым, как то ball.SetSpeed(ball.SetSpeed().VectorSumm((canvas,GetSumForce().VectorDivide(ball.GetMass())).VectorMultiply(timespanner.GetTickPeriod()))) вместо адекватного математического ball.Speed += (canval.SumForce / ball.Mass)* timespanner.TickPeriod - Если в одном месте поменяется имя переменной, то придется менять все Getterы и Setterы, и даже в IDE автоматические замена вам не поможет, в то время как property-свойство - нормальный член класса и его можно отслеживать и переименовывать по всему проекту Никто не заставляет никого следовать определенным стилям в плане объема использования синтаксического сахара, более того как правила таковой сахар - большое зло, особенно в языках более высокого уровня К примеру, на дух не переношу бессмыслпенные сахарные залежи вроде Jquery или CoffeeScript - того же обычного EcmaScript хватает для любых целей за глаза Но в случае C++ property-свойства удобный и органичный механизм, такой же как и все остальные механизмы, основанные на перегрузке операторов Более того в случае с работы с UI-интерфейсом, доступ к свойствам часто осуществляется по их имени в сторковом эквивалентном трактовании, а http://habrahabr.ru/post/125880/ позволяет реализовать и это; по аналогичной причине по всех UI-шных версиях C++ - MSVC++, BorlandC++, Qt - в обязательном порядке есть языковая поддержка property-свойств |
| Автор: Lukkoye 22.11.2014, 22:53 | ||||
В корне неверная мысль. Можно конечно посчитать, что сам по себе высокоуровневый язык - это сахар над машинными кодами. Но это неверно, потому что высокоуровневый язык отличается от машинных кодов парадигмой.
На языке си я могу реализовать объектно ориентированную архитектуру приложения. И это несмотря на то, что сам по себе язык из коробки ООП не умеет. Тем не менее реализовать можно, и существуют различные библиотеки, которые эту возможность используют. Например GTK: https://ru.wikipedia.org/wiki/GTK+ Однако, вы когда нибудь пробовали реализовать оо-архитектуру вручную? Что дает нам нативная поддержка ООП в с++ ? Вы очень ошибаетесь, если полагаете, что это "просто сахар". Это не просто сахар. Это действующая автоматика, благодаря которой, становится возможным , например, реализовать идеому RAII. На языке си можно имитировать ооп, то есть это всего лишь дешевая подделка. Никакой автоматики, все делается вручную. Плюсовый ооп - это не просто сахар. Это - технология, которая принципиально не доступна процедурному си. Я специально несколько раз делал акцент: проперти на языке с++ не дают ничего принципиально нового. Ничего такого, что вы не могли бы сделать при помощи обычных сеттеров/геттеров. Понимаете? ООП в с++ делает возможным вещи, которые принципиально не доступны процедурному си. А ваши проперти ничего такого принципиального нового не привносят. Таким образом ваше сравнение не корректное. Мухи отдельно, котлеты отдельно. Добавлено @ 23:01
Сама по себе технология, благодаря которой стало возможным перегружать функции - это не сахар. Это - технология. То о чем вы пишите - это следствия технологии в действии. И отличительная особенность заключается в простоте. Перегрузка функций столько же проста, как и просто создание функций. Грубо говоря, вам разрешили создавать функции с одинаковыми именами. Вы понимаете смысл? Вы не понимаете. Если бы вы понимали смысл, тогда вы бы поняли: изготовление пропертей, и эксплуатация приводит к усложнению кода. Использование перегруженных функций не приводят к усложнению кода. Если бы создать и использовать (и главное - это использовать) проперти было бы так же легко, как и обычные сеттеры-геттеры, тогда возможно проперти бы и прижились. Но они создают гемморой. Нахрена, если можно получить все тоже самое, только проще? |
| Автор: Lukkoye 22.11.2014, 23:15 | ||||||||
И чем это отличается от:
? Или вас смущает, что в вашем первом варианте вы использовали более длинные имена, и похоже не осилили ссылочные типы с++ ? Так то фактическая длина имени не имеет значение. Автодополнение позволяет быстро вбивать имена любой длины. Значение имеет лишь читабельность. И что касается многочисленной формуло-подобной ботвы, то лично я предпочитаю формуло-подобный стиль код:
Может быть пример не очень удачный. Смысл в том, что "матиматическая формула" должна внешне быть похожей на математическую Поэтому, я часто делаю ссылки на длиные имена, и составляю формлулу из однобуквенных, так она действительно становится похожей на математическую. А поскольку длинные имена-оригиналы тут же, перед глазами, то никаких проблем с читабельностью не возникает. Добавлено @ 23:26
Не понял этого сообщения. Перефразируйте описания проблемы. Не удобный, и сильно ограниченный в возможностях костыль, который совершенно напрасно усложняет код, и создает проблемы. |
| Автор: Lukkoye 22.11.2014, 23:43 | ||
| А что касается _г_о_в_н_о_кода на хабре, то я даже не стал рассматривать реализацию. Я посмотрел только на использование (последний кусок кода, который содержит main). Просто сравните дизайн:
Вот так должен выглядеть приличный GUI на языке с++. Просто и понятно. |