Неплохие аналогии, со многим согласен.
Сам долго катался на этом лифте и когда-то был большим фанатом этого языка.
Просто есть этажи выше, куда С++ увы уже не довезет.
А мировоззрение (как и наркотик) имхо надо регулярно менять.
|
Неплохие аналогии, со многим согласен.
Сам долго катался на этом лифте и когда-то был большим фанатом этого языка.
Просто есть этажи выше, куда С++ увы уже не довезет.
А мировоззрение (как и наркотик) имхо надо регулярно менять.
The future is already here - it is just unevenly distributed. (c) W. Gibson
добавление свойств рефлексивности в язык (т.е. возможность перестройки синтаксиса на лету путем прямого доступа синтаксического препроцессора к ядру компилятора) дает намного больше в плане создания собственных языков.
Темплейты по сравнению с этим кажутся убогими и вызывают жалость.
Теоретически это возможно и в С++, даже было сделано в проекте OpenC++, однако пользоваться этой штукой в С++ крайне затруднительно.
Примерно как писать шелл-скрипт на С++ интерпретаторе
В какой-то момент С++ мог пойти по этому пути, но теперь поздно.
The future is already here - it is just unevenly distributed. (c) W. Gibson
Вы меня извините, но по моему это в все в пользу бедных
Экспертная система в первую очередь зависит от выбранного "экспертного алгоритма", а реализовать ее можно хоть на том же Ц (для мазохистов). А Ц++ тут как раз не самый последний (хотя, возможно и не первый). Вообще "экспертная система" - понятие растяжимое. Я лично был знаком с комрадами, которые лет десять назад писали экспертную систему на Ц++ - и ниче, не жужжали.
"Сложные транзакции" - это вообще в афоризмы.![]()
по моему, Вы тут путаете мух с котлетами.
насколько я понимаю рефлексивность, так это возможность из кода исследовать тип объекта. Посмотреть его поля, методы, свойства, аттрибуты (т.е. так как это в дотнете делается), вызывать методы. Это, вероятно, было бы в Ц++, полезно. Особенно для задач сериализации. А то обычный RTTI довольно бедный (т.е. практически вообще "никакой")
если Вы имеете ввиду генерацию кода на лету в виде низкоуровневых команд (как в дотнете Reflaction.Emit), то у ГНУ был подобный проект. Название, извините, запамятовал.
Разбор кода (его текста) в синтаксическое дерево, модификация дерева и обратно генерация текста (в дотнете CodeDom) - тоже не проблема. Погуглите, к примеру, проект SUIF. Но к рефлексии это не относится.
Компиляция куска кода на лету - вообще не вопрос. только зачем?
совершенно верно Гуффи,
на с++ можно писать все что угодно, и экспертные системы, и рефлективность,
вопрос только зачем? Можно и на с писать. ну и что?
существуют для каждой задачи свой набор инструментов, и иногда надо писать на с иногда на с++, а иногда и на каком нибудь АспектJ.
Нет универсального языка, и это хорошо.
а чаще всего, проишодит так, приходишь на фирму. а там уже весь фреймворк на яве, вот и пишешь дальше на ней, и никакой пролемы выбора.
"Эт точно" (с) Сухов
рефлексивность изанчально в исследовательских работах понималась как возможность языка модифицировать собственную грамматику (extensible compilers/interpreters). К генерации кода на лету (JIT-компиляторы) это не имеет никакого отношения. Когда в массы пришло ООП, этот термин стал более узким - он понимается как метаобъектные протоколы, дающие доступ к структуре класса (а не объекта). Реально это намного меньше, чем extensible compiler, позволяющий не только разбирать собственные исходные тексты, но и модифицировать грамматику.
SUIF действительно может похожие вещи, хотя его цели определены несколько расплывчато (An Infrastructure for Research on Parallelizing and Optimizing Compilers??), как и многие аналогичные проекты он выглядит чисто исследовательским проектом.
The future is already here - it is just unevenly distributed. (c) W. Gibson
изначально и автомобиль подразумевался не как роскошь, а как средство передвижения
и рефлексия в широкой жизни - это сейчас что имеем, то имеем. а не то что подразумевалось в работах великих фантастов
кстати точка зрения, что каждой задаче - свой язык, достаточно разумна и я ее всячески поддерживаю.
Однако есть ряд подводных камней.
Допустим такая задача (реалистичная).
Нужно сделать экспертную систему (ЭС).
Дерево решений должно быть оптимизировано по алгоритму построения минимального дерева решений c4.5
Даные на вход - куча текста.
много математики и статистики, работа с матрицами.
процедуры работы с онтологией должны быть получены генетическим программированием (ГП).
Что имеем.
ЭС - пролог.
с4.5 - стандартная реализация на С.
куча текста - перл.
математика - matlab/octave.
ГП - лисп.
каждый из этапов пишется легко. Практически каждый из предметных языков не типизирован и позволяет быстро ваять прототипы и модели, на которых просто отладить алгоритмы и найти удовлетворительные параметры.
А вот как связать все это вместе?
Кроме того заказчик хочет видеть у себя самодостаточную прикладуху с гуем, а не набор рекомендаций по установке пролога, перла и лиспа.
Я в таких случаях пишу каждый кусок на прикладном языке, а вот потом, когда в модели все отстроено и работает, ручками перевожу в один низкоуровневый язык. С++ или С. Можно автоматом, но опыт показывает, что ручками лучше и не намного дольше, плюс прибавляет понимания как это на самом деле работает.
Что интересно, если не касаться ГУИ, то использование С++ в данной технологии в качестве конечного языка не дает практически никакого выигрыша по сравнению с С - все структуры и отношения к этому моменту уже расписаны и логика программы и каждой компоненты абсолютно прозрачна. Если я знаю например параметры хеша, то мне не нужен С++ map, мне лучше взять более низкоуровневую реализацию с прогнозируемыми параметрами.
С ГУИ однако ситуация меняется, увы. Имхо если бы производители ГУИ работали бы так же как и производители BLAS-реализаций, мир был бы другим.![]()
The future is already here - it is just unevenly distributed. (c) W. Gibson
А работаем в одиночку или бандой в 40 человек?
ИМХО, если бандой,
то уже одно использование управления видимостью
(шлепни по рукам соседа private-ом!)
дает колоссальное приемущество.
Замечание в документации: "не трогай эту глобальную переменную:
она моя и временная", -
приятель может не заметить,
а ошибку компиляции проигнорировать не возможно!
больше 10 человек банда никогда не собиралась. Имхо это не такие задачи которые решаются грубой силой и шеренгами негров-кодеров в кубиклах. За время, которое пройдет в попытках объяснить негру почему все-таки map не надо использовать можно его кусок кода самому написать.
А для С изоляция может быть (и должна быть) более строгой, чем для С++.
private виден в hh-файле, а typedef void* mytype не дает никакой информации о содержимом кроме интерфейса. Плюс отсутствие перекомпиляции при добавлении приватных методов/членов и соответственно более прозрачное разбиение на компоненты.
На С++ это можно сделать только используя чистые интерфейсы, а не классы, что имхо более геморройно и провоцирует на множественное наследование интерфейсов. А это тоже не всегда хорошо.
Плюс замечание в документации - не трогать exceptions.
Хотя везде есть свои недостатки. Я не утверждаю, что С идеален, но в данном варианте разработки (а он тоже имеет проблемы, например большЕе время создания продукта) мне С++ никаких преимуществ не дает.
Возможно в проектах типа системы управления авиалайнером, где заняты тысячи человек это не работает.
The future is already here - it is just unevenly distributed. (c) W. Gibson
вроде не жаловались
поинтер void*, порождает большие проблемы, особенно в больших проектах.
Паттерн pimpl, пректрасно решает "отсутствие перекомпиляции при добавлении приватных членпв/методов".
Не более гоморойно, чем выражать виртуальность в чистом С.
Давай конкретно, возьми любй пример применения виртуальности, и перепиши его на С. а потом подсчитай количество строк в примере и у себя.
Специально для Ull9 - ответы на вопросы
1. виртуальные функции
декларация
странно, одинаковое количество строк.Код://код на С++ class foo { virtual int bar(int par); }; //код на С struct foo { int (*bar)(struct* this,int par); };
имплементация
тоже самое.Код://C++ int foo::bar(int par) { ... } //C int bar_instance(struct* this,int par) { ... }
вызов
тоже самое.Код://C++ foo_inst.bar(4); //C (*foo_inst.bar)(&foo_inst,4);
синтаксический сахар, короче.
единственная где возникает оверхед по строкам (одна строка), это в динамическом инициализаторе/конструкторе (если он есть). В С я должен явно написать foo_inst->bar=bar_inst; Все.
Если же инициализация статическая, то и там оверхеда нет.
Зато свежеобученный или натасканный собеседованиями С++-ник начинает лепить наследование везде, где только можно. С виртуальными членами и абстрактными классами (причем в половине случаев забывая виртуальные деструкторы со всеми вытекающими последствиями :- ).
А на С - использование виртуалок - редкая практика, в полном соответствии с заветами отцов ООП - использовать композицию вместо наследования везде, где это возможно.
2. Private implementation
Паттерном эта штука называется редко, обычно используется термин "идиома". На кой черт потребовалось давать этому примитиву специальную аббревиатуру - вопрос к имиджмейкерам маркетинговых отделов соответствующих фирм.
В правильном дизайне (хе-хе) он нафиг не нужен, так как эта проблема должна решаться интерфейсами. И только.
Имхо PIMPL - заплатка на плохом дизайне.
Что характерно, в С обычно используется именно "интерфейсный подход", там такой штуки как PIMPL я еще не встречал, да она и не нужна.
Т.е. использование С- кода вида
эквивалентно С++ коду.Код:typedef void* opaque_foo; opaque_foo opaque_foo_new(void); int opaque_foo_delete(opaque_foo); int opaque_foo_dosomething(opaque_foo);
Код:// ничего, что я дефайны юзаю? #define interface struct; interface opaque_foo { opaque_foo(void) virtual ~opaque_foo(void)=0; virtual dosomething(void)=0; }
Последний раз редактировалось homo ludens; 07.05.2007 в 09:57. Причина: забыл указатель в коде
The future is already here - it is just unevenly distributed. (c) W. Gibson
Prezhde vsego proshu proshhenija za translit, tut na AIX naprjazhenka s russkimi bukvami..
Nee. tak delo nepojdet. u ob'ekta dolzhno byt' sostojanie. i togda povtori kod na c!
primer:
class Isound
{
public:
virtual void sound() =0;
virtual ~Isound(){}
}
class dog:public Isound
{
const char s;
void sound () {printf(s);}
public:
dog::dog():s("Gav"){}
}
class cat:public Isound
{
const char s;
public:
dog::dog():s("Mjau"){}
void sound () {printf(s);}
}
int main()
{
Isound *f = new dog;
f->sound();
delete f;
f = new cat;
f->sound();
delete f;
}
posle jetogo podschitaj stroki. na C.
odin vopros ostalsja neotvechennym, void* est' zlo. sporit' budem?
pimpl idioma ili pattern sporit ne budu, plohoj dizajn ili net, tozhe. inogda naprimer on vynuzhdennyj. kak na AIX.
i poslednee, kod kotoryj priveden toboj C i C++, mozhet jekvivalentny mozhet i net. vse reshaet chto za obekty za c++ interfejsom.
Последний раз редактировалось Ull9; 07.05.2007 в 14:20.
ответ разобью на 2 части.
итак твой пример. Я чуть подправил, чтобы компилилось без ошибок.
34 строкиКод:#include <stdio.h> class Isound { public: virtual void sound() =0; virtual ~Isound(){} }; class dog:public Isound { const char *s; void sound () {printf(s);} public: dog::dog():s("Gav\n"){} }; class cat:public Isound { const char *s; public: cat::cat():s("Mjau\n"){} void sound () {printf(s);} }; int main() { Isound *f = new dog; f->sound(); delete f; f = new cat; f->sound(); delete f; }
имхо здесь свалены в кучу две вещи - использование интерфейсов и виртуалки.
Сначала виртуалки.
На С виртуалки в данном примере не нужны вообще - есть внутреннее состояние, которое полностью определяет поведение объекта. Без скрытия внутренних структур код такой:
37 строк - на С аж на 3 строки больше.Код:#include <stdio.h> #include <stdlib.h> typedef struct { const char *snd; } sound_t; void sound_print(sound_t* s) { printf("%s\n",s->snd); } sound_t* new_dog(void) { sound_t* rv=malloc(sizeof(sound_t)); rv->snd="Gav!"; return rv; } sound_t* new_cat(void) { sound_t* rv=malloc(sizeof(sound_t)); rv->snd="Mjay!"; return rv; } int main(void) { sound_t* f=new_dog(); sound_print(f); free(f); f=new_cat(); sound_print(f); free(f); return 0; }
Согласись, что если бы ты писал в нормальном стиле, не описывая члены класса в определении класса, на С получилось бы меньше.
теперь о интерфейсах.
Если реализовать скрытие через интерфейс, то в твоем примере интерфейсный класс Isound был бы вынесен в отдельный hh-файл.
На С это выглядело бы так.
в этом варианте получается строк больше, однако у тебя тоже по файлам не разбито.Код:// snd.h - интерфейсы typedef void* sound_t; void sound_print(sound_t* s); sound_t* new_dog(void); sound_t* new_cat(void); // snd_int.h - внутренние структуры, скрытые от пользователя #include <stdio.h> #include <stdlib.h> #include "snd.h" typedef struct { const char *snd; } sound_int_t; void sound_print(sound_t* s) { printf("%s\n",((sound_int_t*)s)->snd); } sound_t* new_dog(void) { sound_int_t* rv=malloc(sizeof(sound_int_t)); rv->snd="Gav!"; return (sound_t*)rv; } sound_t* new_cat(void) { sound_int_t* rv=malloc(sizeof(sound_int_t)); rv->snd="Mjay!"; return (sound_t*)rv; } // пользовательский код, доступа к внутренним структурам не имеет. #include <stdlib.h> #include "snd.h" int main(void) { sound_t* f=new_dog(); sound_print(f); free(f); f=new_cat(); sound_print(f); free(f); return 0; }
имхо надо более реалистичный пример.
например у меня предполагается отсутствие деструктора, память освобождается через free, это не всегда верно для сложных структур. С другой стороны у тебя тоже деструкторы не используются. И т.п.
The future is already here - it is just unevenly distributed. (c) W. Gibson
Социальные закладки