Здравствуйте, kov_serg, Вы писали:
_>- для скрытия реализации _>
_>class A {
_> List list; // потом могу переделать по другому и в других местах ничего не меняем.
_> public void Add(object a) { list.Add(); }
_> property int Count { get { return list.Count; } }
_>}
_>
Дык это,
_>class A {
List list; // потом могу переделать по другому и в других местах ничего не меняем.public:
void Add(object a) { list.Add(); }
int Count() const { return list.Count; }
};
_>- Что бы не писать функции getX setX _>
_>struct SomeInterface {
_> virtual int getX()=0;
_> virtual int setX(int x)=0
_>};
_>
Это я не понял, к чему и зачем.
_>было _>
_>class A {
_> public int X;
_>};
_>
Что за проблема?
Пишешь шаблон, типа
template<typename T> class debug_wrapper {
private:
T data;
protected:
T& Data() { return data; }
const T& Data() const { return data; }
public:
// тут кучка конструкторов, с вынесенным определением тела
// тут кучка операторов, с вынесенным определением телаoperator const T&() const { return Data(); }
operator T&() { return Data(); }
};
Вклюяаешь это в свои любимые отладочные тузы. И потом пишешь что-то типа:
class A {
public:
struct xxx_prop : debug_wrapper<int> {
void operator = ( int newValue )
{
this->Data() = newValue;
}
} X;
};
А если немного больше поработать, то можно сделать так, что можно будет написать таким образом:
_>class A {
_> int x;
_> public int X { get { return x; }
_> set {
_> if (value==100)
_> Debug.BreakPoint();
_> x=value;
_> }
_> }
_>}
_>
А тут вообще не факт, что какой-то клиентский код не нагнётся.
_>- Можно использовать для валидации и оповещении об измении поля. _>
_>class A {
_> int x;
_> Validator validator;
_> Notifier notifier;
_> public int X { get { return x; }
_> set {
_> validator.validate(x);
_> if (x!=value) {
_> x=value;
_> notifier.notify_subscribers();
_> }
_> }
_> }
_>}
_>
Мульку с шаблоном можно точно так же.
_>при этом из вне синтаксис как к обычному полю a.X=a.X+1;
Только это вот и плохо.
Совсем нет никакого желания, добавить в язчк такую граблю, что a.X++ может без объявления войны превратиться в какое-то чудовище... _>и внутренние изменения переход от поля к гетерам и сетерам не приводит к изменению остального кода.
Это неправда.
Вот представь себе, например, что надо куда-то отдать int* для заполнения
Все эмоциональные формулировки не соотвествуют действительному положению вещей и приведены мной исключительно "ради красного словца". За корректными формулировками и неискажённым изложением идей, следует обращаться к их автором или воспользоваться поиском
E>Коротко, ясно и для интеропа с другими языками лучше приспособленно...
вот так обычно в с++ так и заканчиваются решения простых задач: изврат и разведение рук
Я изъездил эту страну вдоль и поперек, общался с умнейшими людьми и я могу вам ручаться в том, что обработка данных является лишь причудой, мода на которую продержится не более года. (с) Эксперт, авторитет и профессионал из 1957 г.
Здравствуйте, Kingofastellarwar, Вы писали:
K>>>как просто у вас, а если вам интерфес нужен а не класс?
E>>[ccode] E>>class IService E>>{ E>>public: E>> virtual IMemeber* GetMember() = 0; E>>};
K>вот так обычно в с++ так и заканчиваются решения простых задач: изврат и разведение рук
В чём изврат?
В С++ это стандартный способ интерфейса к аггрегированному объекту...
Все эмоциональные формулировки не соотвествуют действительному положению вещей и приведены мной исключительно "ради красного словца". За корректными формулировками и неискажённым изложением идей, следует обращаться к их автором или воспользоваться поиском
E>Например, почему бы не иметь возможности работать с типами в СТ, как-то их декоспозицию осуществлять, менять и т. д. E>Какие-то такие возможности даёт шаблонная магия, но очень бледные.
Я с этим я, кстати, не спорю. Например, я в упор не понимаю, почему превратить тип в const и получить ссылку на него можно с помощью встроенных средств языка, а наоборот — только путем шаблонов и их специализации. А это плохо по целому ряду причин, включая отсутствие нормальной диагностики ошибок.
Пример — я хочу объявить шаблонную функцию, принимающую аргумент исключительно по неконстантной ссылке — потому что внутри я буду его менять.
Попытка:
template <class T>
void n1(T& t) {
++t;
}
И не дай бог кто-то вызовет эту функцию с константным аргументом, например:
const int i = 10;
n1(i)
Ошибка отрепортится в недрах n1, со всем счастием репортов из шаблонов.
А мне нужно, чтобы я мог написать что-то вроде n1(non_const T& ) — и компилятор четко сказал, что тип требуется неконстантный. Я многого хочу?
E>Потом рефлексия. Почему бе не дать, хотя бы в СТ возможность проитерировать все методы класса, например?
Теоретически да. Практическая польза невелика в связи со всяким увлекательным наследованием.
Здравствуйте, Vamp, Вы писали:
E>>Потом рефлексия. Почему бе не дать, хотя бы в СТ возможность проитерировать все методы класса, например? V>Теоретически да. Практическая польза невелика в связи со всяким увлекательным наследованием.
Ну вот представь себе, что был бы какой-то механизм миксинов.
Скажем, такой хитрый шаблон, который всегда применяеся к MDT, как-то перебирает его интерфейс и модифицирует его.
Все эмоциональные формулировки не соотвествуют действительному положению вещей и приведены мной исключительно "ради красного словца". За корректными формулировками и неискажённым изложением идей, следует обращаться к их автором или воспользоваться поиском
Здравствуйте, Vamp, Вы писали:
V>Ошибка отрепортится в недрах n1, со всем счастием репортов из шаблонов. V>А мне нужно, чтобы я мог написать что-то вроде n1(non_const T& ) — и компилятор четко сказал, что тип требуется неконстантный. Я многого хочу?
Ну в C++11 вроде выдали костыли для этого (type traits), в бусте и так давно были.
Переубедить Вас, к сожалению, мне не удастся, поэтому сразу перейду к оскорблениям.
Здравствуйте, Ops, Вы писали:
Ops>Ну в C++11 вроде выдали костыли для этого (type traits), в бусте и так давно были.
Криво всё это и сложно.
Все эмоциональные формулировки не соотвествуют действительному положению вещей и приведены мной исключительно "ради красного словца". За корректными формулировками и неискажённым изложением идей, следует обращаться к их автором или воспользоваться поиском
Здравствуйте, Vamp, Вы писали:
V>Я с этим я, кстати, не спорю. Например, я в упор не понимаю, почему превратить тип в const и получить ссылку на него можно с помощью встроенных средств языка, а наоборот — только путем шаблонов и их специализации. А это плохо по целому ряду причин, включая отсутствие нормальной диагностики ошибок. V>Пример — я хочу объявить шаблонную функцию, принимающую аргумент исключительно по неконстантной ссылке — потому что внутри я буду его менять.
Всё не совсем так уж плохо.
V>И не дай бог кто-то вызовет эту функцию с константным аргументом, например:
и всё будет хорошо, но всё равно геморрно так писать.
V>
V>const int i = 10;
V>n1(i)
V>
Все эмоциональные формулировки не соотвествуют действительному положению вещей и приведены мной исключительно "ради красного словца". За корректными формулировками и неискажённым изложением идей, следует обращаться к их автором или воспользоваться поиском
Здравствуйте, Erop, Вы писали:
_>>- Что бы не писать функции getX setX _>>
_>>struct SomeInterface {
_>> virtual int getX()=0;
_>> virtual int setX(int x)=0
_>>};
_>>
E>Это я не понял, к чему и зачем.
что бы запись была более короткой
int X { get; set; }
E>Что за проблема?
точно что за проблема есть же макроассемблер.
компилятор должен упрощать написание кода, а не наоборот.
я всего лишь хочу что бы простые вещи записывались просто.
E>Пишешь шаблон, типа
template<typename T> class debug_wrapper {
E>private:
E> T data;
E>protected:
E> T& Data() { return data; }
E> const T& Data() const { return data; }
E>public:
E> // тут кучка конструкторов, с вынесенным определением тела
E> // тут кучка операторов, с вынесенным определением тела
E> operator const T&() const { return Data(); }
E> operator T&() { return Data(); }
E>};
главная проблема очень простая — я не могу достать класс родитель из этого wrapper-а
мне универсальность не нужна. просто под конкретную задачу написано.
... _>>стало _>>
_>>class A {
_>> int x;
_>> public int X { get { return x; }
_>> set {
_>> if (value==100)
_>> Debug.BreakPoint();
_>> x=value;
_>> }
_>> }
_>>}
_>>
E>А тут вообще не факт, что какой-то клиентский код не нагнётся.
не нагнётся.
_>>- Можно использовать для валидации и оповещении об измении поля. _>>
_>>class A {
_>> int x;
_>> Validator validator;
_>> Notifier notifier;
_>> public int X { get { return x; }
_>> set {
_>> validator.validate(x);
_>> if (x!=value) {
_>> x=value;
_>> notifier.notify_subscribers();
_>> }
_>> }
_>> }
_>>}
_>>
E>Мульку с шаблоном можно точно так же.
и как?
_>>при этом из вне синтаксис как к обычному полю a.X=a.X+1; E>Только это вот и плохо. E>Совсем нет никакого желания, добавить в язык такую граблю, что a.X++ может без объявления войны превратиться в какое-то чудовище...
любой инструмент можно использовать не по назначению.
поэтому мне больше всего нравится связка C + lua. низкоуровневый язык без заморочек + просто динамический легко расширяемый язык, который позволяет описывать всякую ерунду (которой обычно много во всяких ui), коротко и ясно. при этом эта ерунда не требует высокого быстродействия.
Оба языка просто портируются, имеют низкий порог вхождения.
_>>и внутренние изменения переход от поля к гетерам и сетерам не приводит к изменению остального кода. E>Это неправда. E>Вот представь себе, например, что надо куда-то отдать int* для заполнения
легко представляю. но это всего лишь особенность языка. да и потом там где используются пропертя указатели на них нафиг не нужны.
замена int на хитрую структуру тоже на поведётся на int*.
Здравствуйте, kov_serg, Вы писали:
_>что бы запись была более короткой _>
_>int X { get; set; }
_>
Запись
struct XXX {
int X;
};
ещё короче...
Все эмоциональные формулировки не соотвествуют действительному положению вещей и приведены мной исключительно "ради красного словца". За корректными формулировками и неискажённым изложением идей, следует обращаться к их автором или воспользоваться поиском
Здравствуйте, kov_serg, Вы писали:
E>>Что за проблема? _>точно что за проблема есть же макроассемблер. _>компилятор должен упрощать написание кода, а не наоборот. _>я всего лишь хочу что бы простые вещи записывались просто.
IMHO, пропертя -- это не просто, а наоборот, оч. сложно.
_>главная проблема очень простая — я не могу достать класс родитель из этого wrapper-а
_>а для каждого поля делать указатель накладно, и неудобно инициализировать.
А зачем он нужен?
Ты привёл несколько примеров использования пропертей, там нигде аггрегирующийй обект нужен не был...
_>мне универсальность не нужна. просто под конкретную задачу написано.
IMHO, просто не надо пропети под С++ использовать. Идея сама по себе против шерсти.
Надо брать нужные юз-кейсы и смотерть, как удобно их сделать другими средствами.
Хотя я согласен, что в С++ можно было бы добавить механизм, который бы позволял из поля найти this объемлющего объекта, но тогда полю пришлось бы иметь уникальный тип. Ну да и фиг бы с ним.
E>>А тут вообще не факт, что какой-то клиентский код не нагнётся. _>не нагнётся.
Откуда следует, что не нагнётся?
E>>Мульку с шаблоном можно точно так же. _>и как?
Подписываешь в конструкторе объекта агрегатора на уведомлени от полей того, кого надо...
E>>Вот представь себе, например, что надо куда-то отдать int* для заполнения _>легко представляю. но это всего лишь особенность языка. да и потом там где используются пропертя указатели на них нафиг не нужны. _>замена int на хитрую структуру тоже на поведётся на int*.
Да. Я вообще считаю подход с пропертями тухлым. Архитектурной ошибкой.
Правила поведения системы, вместо того, что бы быть где-то декларативно выписанными, размазываются по каким-то левым сеттерам и геттерам.
Все эмоциональные формулировки не соотвествуют действительному положению вещей и приведены мной исключительно "ради красного словца". За корректными формулировками и неискажённым изложением идей, следует обращаться к их автором или воспользоваться поиском
Здравствуйте, Kingofastellarwar, Вы писали:
E>>class CService : public IService E>>{ E>> CMember MemberImpl; E>> virtual IMemeber* GetMember() { return &MemberImpl; } E>>};[/ccode] E>>Коротко, ясно и для интеропа с другими языками лучше приспособленно...
K>вот так обычно в с++ так и заканчиваются решения простых задач: изврат и разведение рук
Чувак, другой язык это не другой синтаксический сахарок но и другая парадигма.
Здравствуйте, johny5, Вы писали:
J>Чувак, другой язык это не другой синтаксический сахарок но и другая парадигма.
с такими фразами лучше в политику, "парадигмой" я могу оправдать всё что угодно и где угодно
Я изъездил эту страну вдоль и поперек, общался с умнейшими людьми и я могу вам ручаться в том, что обработка данных является лишь причудой, мода на которую продержится не более года. (с) Эксперт, авторитет и профессионал из 1957 г.
Здравствуйте, Erop, Вы писали:
E>Хотя я согласен, что в С++ можно было бы добавить механизм, который бы позволял из поля найти this объемлющего объекта, но тогда полю пришлось бы иметь уникальный тип. Ну да и фиг бы с ним.
Именно так я накидал PROPERTY макро:
#define PROPERTY(PropertyName, OwnerType_, Type, InternalType, GetterName, SetterName) \
template<typename OwnerType>
struct Property##PropertyName : public PropertyValueHolder__<InternalType>
....
... //указатель на родительский класс получается вот такconst OwnerType* get_owner_this() const
{
return (const OwnerType*)(((const char*)this) - OFFSETOF(OwnerType, OwnerType::PropertyName));
}
.. // класс с уникальным именем
Property##PropertyName <OwnerType_> PropertyName;
и с помощью трюка что шаблонные функции инстанциируются только в месте использования, вполне легально было заюзать OFFSETOF на ещё не доопределённый класс.
Замечательно работало, правда использовал лишь единожды да и помоему позднее таки выкинул.
Если нужно, могу впостить код целиком.
Здравствуйте, Kingofastellarwar, Вы писали:
K>с такими фразами лучше в политику, "парадигмой" я могу оправдать всё что угодно и где угодно
Ты опять не понимаешь, языки это не синтаксические сахарки к одному и тому же. Вот ты хочешь от С++ то-же, что сделано в С# но только чтобы "быстрее". Разве ты сам не видишь тут противоречия?
С++ проектировался (парадигма была такая), чтобы быть быстрее.
С# проектировался, чтобы мм.. быть доступнее начинающим.
Вот вы даже в оригинальном посте поленились указатели расставить, видно что внимания к этому вопросу (принципам программирования на С++) совсем нет, нуно просто склепать. Я вам предложу вариант, именно то что вы хотели — без виртуального вызова:
class IService
{
public:
IMemeber* const Member;
protected:
IService(IMember* m) : Member(m) {}
};
class CService : public IService
{
CMemberImpl member;
public:
CService() : IService(&member)
{}
}
но это лютый изврат. Вариант Егора лучше — он понятнее (в парадигме), так обычно спрашивают доп. интерфейс у объекта.
Можно ещё поплясать на множественном наследовании, отнаследовать несколько интерфейсов и спрашивать их через dynamic_cast<>
class IService
{
virtual something_else...
};
class CService : public IService, CMemberImpl
{
}
либо написать свою реализацию virtual QueryInterface(enum.. );, либо инкапсулировать интерфейсы друг в друга.
Вообще имхо подобная проблема возникает редко, нужно бы посмотреть под капот, откуда он такой возникает и избавиться от него. У меня есть некие преположения почему подобные извраты вдруг потребовались...
Здравствуйте, johny5, Вы писали:
J>Здравствуйте, Kingofastellarwar, Вы писали:
K>>с такими фразами лучше в политику, "парадигмой" я могу оправдать всё что угодно и где угодно
J>Ты опять не понимаешь, языки это не синтаксические сахарки к одному и тому же. Вот ты хочешь от С++ то-же, что сделано в С# но только чтобы "быстрее". Разве ты сам не видишь тут противоречия?
J>С++ проектировался (парадигма была такая), чтобы быть быстрее. J>С# проектировался, чтобы мм.. быть доступнее начинающим.
J>Вот вы даже в оригинальном посте поленились указатели расставить, видно что внимания к этому вопросу (принципам программирования на С++) совсем нет, нуно просто склепать. Я вам предложу вариант, именно то что вы хотели — без виртуального вызова:
J>
J>но это лютый изврат. Вариант Егора лучше — он понятнее (в парадигме), так обычно спрашивают доп. интерфейс у объекта.
он не прокатит в куче случаев, например если у нас
CMemberImpl * member;
а не
CMemberImpl member;
придется писать
IMemeber** const Member;
а это порно
Я изъездил эту страну вдоль и поперек, общался с умнейшими людьми и я могу вам ручаться в том, что обработка данных является лишь причудой, мода на которую продержится не более года. (с) Эксперт, авторитет и профессионал из 1957 г.
K>он не прокатит в куче случаев, например если у нас
K>CMemberImpl * member; K>а не K>CMemberImpl member;
K>придется писать K> IMemeber** const Member; K>а это порно
Ну если у вас меняется имплементация IMember в рантайме, тогда вариант Егора тут выглядит чище, хоть он и тяжелее из-за виртуального вызова. Можно и было бы просто сбросить константность указателя Member в IService и менять его вместе со сменой имплементации IMember*, избегая двойного указателя.
Только уже опасно, т.к. клиент подобного интерфейса может скэшировать старый указатель. Я бы тогда лучше инкапсулировал IMember интерфейс в IService, чтобы огородить клиента от подобных проблем.
Здравствуйте, johny5, Вы писали:
J>Замечательно работало, правда использовал лишь единожды да и помоему позднее таки выкинул. J>Если нужно, могу впостить код целиком.
UB на UB + виртуальная база всё нагнёт...
Все эмоциональные формулировки не соотвествуют действительному положению вещей и приведены мной исключительно "ради красного словца". За корректными формулировками и неискажённым изложением идей, следует обращаться к их автором или воспользоваться поиском