Модераторы: LSD

Поиск:

Ответ в темуСоздание новой темы Создание опроса
> ООП против Остальных 
:(
    Опции темы
Domestic Cat
  Дата 29.6.2005, 21:09 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Экс. модератор
Сообщений: 5452
Регистрация: 3.5.2004
Где: Dallas, US

Репутация: 4
Всего: 172



Иногда попадаются наезды на ООП... smile Сразу сообщаю что
1. Я "сторонник" ООП
2. Мое глубокое убеждение в том, что каждому инструменту своя задача

Тем не менее, почему ООП, или почему его считают "сложным", "бюрократичным", "махиной" и проч?
А потому что видимо мало кто понимает зачем оно нужно и что конкретно оно дает.
Обьясняю на примере. Я и сам нечто подобное думал написать, но сегодня попался на глаза коммент к статье Джоэла, один в один... Можно считать плагиатом.

Итак, я решаю написать нечто на старом добром С и знать не хочу об ООП. Предположим, мне нужен линкованый список, и у меня в руках нет готовой библиотеки. Естественно, я ввожу нужные переменные и пишу ряд функций типа add(), get(), head(), tail(), count(), и проч. Программа пишется себе пишется, и файлик становится нехилым. Конечно же, я делаю программу модульной, то есть выношу список в отдельный модуль. Далее, оказывается, нужны также хешмап и дерево. Соответственно, они попадают в модули map.c, tree.c Это есть гут, но теперь я начинаю путаться в вызовах методов, ведь каждая из этих коллекций имеет похожие методы add(), remove() и так далее. Выход например такой: переназвать методы в addToTree(), addToMap(), addToLinkedList(). Трудимся, и перелопачиваем все эти файлы.

Далее, оказывается нужен также особый список, содержащий только элементы определенного типа. Нужно создавать отдельный модуль LinkedStringList и методом копипаста переносить в него содержимое предыдущего файла. Естественно, кое где я забываю подправить код, что стоит мне в дальнейшем многих часов дебаггинга.

Далее, вроде все ок, но мне нужно провести поиск по нескольким коллекциям сразу. Простой код поиска в списке необходимо дублировать и для мапа и для дерева, меняя в каждом случае только вызов методов.

Другая проблема в том, я решаю использовать хешмап, написанный Васей (он круче) и по незнанию меняю пару переменных из своего кода, тогда как они нужны самому мапу и ни в коей мере не мне. Упс - хешмап оказывается очень неэффективным! Какого спрашивается? Денек - и ответ ясен, не нужно было трогать этих переменных.

Теперь посмотрим, можно ли упростить наш кот? Можно. Назовем модуль - классом, и создадим объект этого класса. Тогда решается проблема с названиями: вместо addToTree() мы пишем tree.add(), вместо addToStringLinkedList() мы пишем linkedList.add(). Проще? Проще.
Давайте также введем модификаторы доступа: переменные, не предназначенные для публики, объявим private, так что ни Вася, ни Петя не смогут из своего кода напрямую изменить их.
Наконец, введем наследование: объявив класс наследующим от другого класса, мы получаем весь его код без копипаста, и вдобавок можем перегружать определенные функции своими, т.е. подстраивать их под себя.
Но если два класса наследуют от одного и того же класса, они фактически являются этим классом, т.е. как минимум содержат те же методы. Следовательно, их можно рассматривать как класс-родитель. Теперь нам не нужно писать код отдельно для каждого типа коллекции, мы можем привести все эти коллекции к одному базовому типу и вместо трижды повторенного копипастом кода мы имеем один на всех.

Вот и получается, что ООП есть попросту упрощенное процедурное программирование. Конечно, ООП обросло своими специфическими вещеми и своей философией. И это позволило создать громадное количество библиотек за довольно небольшой промежуток времени. Заметьте, только ОО языки превратились в конце концов в "платформы" и "технологии". С помощью Java или C# можно написать любое высокоуровневое приложение - будь то десктоп, веб или корпоративное приложение, база данных или игра. Единственное что отброшено - это низкоуровневость (и скорость по сравнению с С и асмом). Но при настоящем развитии железа это и не нужно.


--------------------

PM   Вверх
Mayk
Дата 29.6.2005, 21:50 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


^аВаТаР^ сообщение>>
****


Профиль
Группа: Участник
Сообщений: 2616
Регистрация: 22.5.2005
Где: за границей разум а

Репутация: 2
Всего: 134



Цитата(Domestic @ 29.6.2005, 22:09)
Естественно, я ввожу нужные переменные и пишу ряд функций типа add(), get(), head(), tail(), count(), и проч.

Это отнюдь не естественно. Взять, например gtk или tuxracer. По их стилю это записалось бы вот так: list_add(), list_get(), etc


Цитата(Domestic @ 29.6.2005, 22:09)
Далее, оказывается нужен также особый список, содержащий только элементы определенного типа. Нужно создавать отдельный модуль LinkedStringList

Не всегда нужен модуль. Нужен препроцессор. И нет никакой правки кода.
Код

#ifndef __stringlist_h
#define __stringlist_h
typedef list_t string_list_t;
typedef list_node_t string_list_node_t;

#define string_list_get(list) (string) list_get(list)
#define string_list_head(list) list_head
//cпецифичные для класса функции
//string_list_node_t* string_list_get_longest_string(string_list_t*);
#endif



Цитата(Domestic @ 29.6.2005, 22:09)
Далее, вроде все ок, но мне нужно провести поиск по нескольким коллекциям сразу. Простой код поиска в списке необходимо дублировать и для мапа и для дерева, меняя в каждом случае только вызов методов.

Код

#define __foreach_start(collection_type_name, __collection_var, __iterator) \
do{\
collection_type_name##_t* __iterator;\
for(__iterator=collection_type_name##_head(__collection_var);__iterator;\
__iterator=__iterator->next)

#define __foreach_end() }while(0)


А вообще я тоже сторонник ООП. Просто препроцессор люблю. Жалко редко удается использовать.

Это сообщение отредактировал(а) Mayk - 29.6.2005, 21:53


--------------------
 Здесь был кролик. Но его убили.
Человеки < кроликов, йа считаю.
PM MAIL WWW ICQ   Вверх
Domestic Cat
Дата 29.6.2005, 21:55 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Экс. модератор
Сообщений: 5452
Регистрация: 3.5.2004
Где: Dallas, US

Репутация: 4
Всего: 172



Цитата(Mayk @ 29.6.2005, 12:50)

Это отнюдь не естественно. Взять, например gtk или tuxracer. По их стилю это записалось бы вот так: list_add(), list_get(), etc


Какая разница, в любом случае название метода менять надо.

Цитата(Mayk @ 29.6.2005, 12:50)
Не нужен модуль. Нужен препроцессор. И нет никакой правки кода.

На препроцессор еще дядя Страуструп ругался smile Хотя да, он же ООПшник smile Но в любом случае препроцесор может сделать код настолько нечитабельным и непонятным, что ужос. По крайней мере разобраться в приведенном тобой коде было бы *очень* сложно, при его чтении нужно было бы держать в памяти все директивы. Я вообще на препроцессорных директивах мозгу почти Java кот написать, отличие будет в одной точке smile
Добавлено @ 22:03
Да и я бы не стал относить препроцессор к процедурному программированию, это фича компилятора не более того.


--------------------

PM   Вверх
S.A.P.
Дата 29.6.2005, 22:11 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Участник Клуба
Сообщений: 2664
Регистрация: 11.6.2004

Репутация: 1
Всего: 71



Сейчас придет Oleg1973 и разьяснит что к чему smile .
PM MAIL   Вверх
Mayk
Дата 29.6.2005, 23:14 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


^аВаТаР^ сообщение>>
****


Профиль
Группа: Участник
Сообщений: 2616
Регистрация: 22.5.2005
Где: за границей разум а

Репутация: 2
Всего: 134



Цитата(Domestic @ 29.6.2005, 22:55)
Какая разница, в любом случае название метода менять надо.

Если ты сразу назовешь ф-ции для работы с листом как list_XXX, а ф-ции для работы с деревом как tree_xxx, то никакой неразбирихе не будет. Это этика написания и её надо придерживаться, иначе даже ООП не спасет.
Пример(Что он делает?):
Код

class dfjdsfjfdsfds{
   double boogieBa, baogieBa, boagieBa;
   double dsada(dfjdsfjfdsfds& dsaba){
          return boogieBa*dsaba.boogieBa+baogieBa*dsaba.baogieBa+boagieBa*dsaba.boagieBa;      
   }
};

Правильно, это скалярное произведение векторов smile
Кстати писать имена классов перед функциями предпочтительнее, потому что так код смотрится красивее(четко видны блоки где что-то делается исключительно с list'ом).

Цитата(Domestic @ 29.6.2005, 22:55)
Но в любом случае препроцесор может сделать код настолько нечитабельным и непонятным, что ужос.

Вот здесь полностью согласен. Препроцессор жутко уродлив и нечитаем особенно если один define идёт на два экрана. Например так сделано во freeciv'е в common/map.h в макросе iterate_outward(freeciv1.13: 36 строк). У него есть еще недостатки:
нельзя делать макросы на ходу, типа
#define aaa(xxx) \
#define aaa_##xxx
А жаль, получилась бы хорошая замена template'ам smile


Цитата(Domestic @ 29.6.2005, 22:55)
По крайней мере разобраться в приведенном тобой коде было бы *очень* сложно

smile
Ну если постараться, то в с++ тоже можно сделать труднопонимаемый код, если наиграться с перегрузкой операторов... Хотя ты кажется уже считал полезность их перегрузки сомнительной smile

Цитата(Domestic @ 29.6.2005, 22:55)
Я вообще на препроцессорных директивах мозгу почти Java кот написать, отличие будет в одной точке smile

Ухх, не врубился.

[QUOTE=Domestic Cat, 29.6.2005, 22:55]
Да и я бы не стал относить препроцессор к процедурному программированию, это фича компилятора не более того.
[/quoute]
Тема называется ООП против остальных. Препроцессор и есть часть остальных smile
Кроме того эта очень мощная фича. Ведь виртуальные функции - это тоже фича. Их можно сделать и вне ООП

Кроме того надо не забывать про недостатки ООП.
1)Переопределение:
class A{ int primeNumber() { return 2;} }
class B:A{ int primeNumber() { return 65539;} }
B* b = new B; A* a = b;
b->primeNumber() = 65539
a->primeNumber() = 2
А это не всегда желательно.
2) Вызов методов для получения и/или установки значений.
Вот пример из sim-0.9.3/sim/api/
Код

//socket.h:
class EXPORT SSLClient : public SocketNotify, public Socket
{ public:
...
    Socket *socket() { return sock; }
    void setSocket(Socket *s);
...
//sslclient.cpp
void SSLClient::setSocket(Socket *s){   
    sock = s; }

Здесь только socket() определена как inline функция. А вот setSocket будет вызываться.
А как с этим дела обстоят в жабке? Там же все функции по умолчанию виртуальны? Значит всевозможные тело getX() нельзя подставить в код заместо вызова, если разработчик библиотеки зазевался(кстати о птичках, пишу в 3 часа ночи) и не развиртуалил функцию(блин, не помню как это называется)


ЗЫ. Ну вот, опять всплыла тема препроцессор против плюсов smile




Это сообщение отредактировал(а) Mayk - 29.6.2005, 23:19


--------------------
 Здесь был кролик. Но его убили.
Человеки < кроликов, йа считаю.
PM MAIL WWW ICQ   Вверх
Domestic Cat
Дата 30.6.2005, 00:00 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Экс. модератор
Сообщений: 5452
Регистрация: 3.5.2004
Где: Dallas, US

Репутация: 4
Всего: 172



Цитата(Mayk @ 29.6.2005, 14:14)
Если ты сразу назовешь ф-ции для работы с листом как list_XXX, а ф-ции для работы с деревом как tree_xxx, то никакой неразбирихе не будет. Это этика написания и её надо придерживаться, иначе даже ООП не спасет.
Пример(Что он делает?):


Предположим, что тебе нужно теперь вместо листа использовать дерево. Придется тебе идти по коду и менять названия методов smile А потом окажется что нужен массив

Цитата(Mayk @ 29.6.2005, 14:14)
Ну если постараться, то в с++ тоже можно сделать труднопонимаемый код, если наиграться с перегрузкой операторов... Хотя ты кажется уже считал полезность их перегрузки сомнительной smile

Плохой кот можно делать на любом языке. smile

Цитата(Mayk @ 29.6.2005, 14:14)
Ухх, не врубился.

Это не С конечно, но иллюстрация к тому, что можно сделать директивами
Код

#define public public : 
#define System cout
#define out operator
#define println <<
#define String char* 
#include <iostream>
using namespace std;
class Test
{
    public Test()
    {
        System.out println(getString());
    }
    
    String getString()
    {
        return "Hello World";
    }
}


Цитата(Mayk @ 29.6.2005, 14:14)
1)Переопределение:
class A{ int primeNumber() { return 2;} }
class B:A{ int primeNumber() { return 65539;} }
B* b = new B; A* a = b;
b->primeNumber() = 65539
a->primeNumber() = 2
А это не всегда желательно.


Если это нежелательно то не надо так делать, нужно метод по-другому назвать. Наоборот, данное свойство позволяет динамически привязывать методы и фактически является основой полиморфизма.


Цитата(Mayk @ 29.6.2005, 14:14)
Здесь только socket() определена как inline функция. А вот setSocket будет вызываться.
А как с этим дела обстоят в жабке? Там же все функции по умолчанию виртуальны? Значит всевозможные тело getX() нельзя подставить в код заместо вызова, если разработчик библиотеки зазевался(кстати о птичках, пишу в 3 часа ночи) и не развиртуалил функцию(блин, не помню как это называется)


Опять таки, это свойство компилятора, к ООП не имеет отношения. То же самое можно сказать и о функциях в С.
Насчет Java - любой объявленный final метод привязывается статически, и JIT делает его inline.


--------------------

PM   Вверх
Mayk
Дата 30.6.2005, 09:51 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


^аВаТаР^ сообщение>>
****


Профиль
Группа: Участник
Сообщений: 2616
Регистрация: 22.5.2005
Где: за границей разум а

Репутация: 2
Всего: 134



Цитата(Domestic @ 30.6.2005, 01:00)
Придется тебе идти по коду и менять названия методов

Ах, ты в этом смысле. Ничего, есть достойное решение и этой проблемы. Search&Replace - selected only smile
Ищем list_, заменяем на tree_.
И все листы становятся деревьями. Не многим сложнее, чем заменить название одного класса, не так ли?
Опять же, еще можно взять препроцессор, а дальше все зависит от фантазии. И, опять же, добавление в лист отличается от добавления к дереву. Так что код придется менять в любом случае.

Цитата(Domestic @ 30.6.2005, 01:00)
Это не С конечно, но иллюстрация к тому, что можно сделать директивами

smile


Цитата(Domestic @ 30.6.2005, 01:00)
Опять таки, это свойство компилятора, к ООП не имеет отношения.

Не соглашусь. Это имеет отношение к ООП, так как ООП предоставляет возможность делать языки программирования в которых легко забыть о том, что getX() будет вызыван и не подставлен. В функциональном программирования виртуальных функций нет как класса, там это невозможно. А препроцессор си гарантированно сделает "функцию" inline'ной. А языки программирования в свою очередь предсоставляют возможность писать библиотеки, в которых getX() не объявлен как финальный. Взять для примера робокот. getX() там НЕ объявлен финальным. Его можно перегрузить, хотя польза от подобной перегрузки весьма сомнительна. Ну я вот не могу придумать зачем отдельно взятому роботу перегружать getX()... (Тем более, что в заблуждение врагов это не вводитsmile)

Ладно, поехали дальше

3) Проектирование классов.
Можно разделить на две подпроблемы - 3.1) не знаешь что куда запихать. Такое иногда случается. Хотя ладно, неудачная реализация классов говорит плохо скорее о создателях либы. В функционалке они бы тоже наверняка напортачили. Просто ООП даёт больше возможностей напортачить. Сиди, гадай как получить, скажем, вес колеса машины: не то Car.getDetailWeight("Wheel1"); не то Car.getGrouppedDetails("Wheels").getSingleDetail(1).weight(), а может колесо вообще деталью не счиатают и надо Car.getWheelWeight().
3.2) непосредственное написание классов.
Это довольно утомительное занятие писать классы, если эти классы тривиальны и большинство функций в них - это get/setы. Пример - математический вектор. В здравом уме в си никто и не подумает писать getX() для вектора. Максимум - это #define vector_getX(vector) ((vector).x). А в ООП здравый ум так делать не будет.





--------------------
 Здесь был кролик. Но его убили.
Человеки < кроликов, йа считаю.
PM MAIL WWW ICQ   Вверх
Domestic Cat
Дата 30.6.2005, 10:07 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Экс. модератор
Сообщений: 5452
Регистрация: 3.5.2004
Где: Dallas, US

Репутация: 4
Всего: 172



Цитата(Mayk @ 30.6.2005, 00:51)

Ах, ты в этом смысле. Ничего, есть достойное решение и этой проблемы. Search&Replace - selected only smile
Ищем list_, заменяем на tree_.

Точнее не название класса, а тип переменной. Но этот самый серч и реплейс не есть выход, речь ведь не о технических средствах... Название методов менять сложнее чем тип переменной

Цитата(Mayk @ 30.6.2005, 00:51)
А препроцессор си гарантированно сделает "функцию" inline'ной.

Во-первых, не всякую функцию, а объявленную так. Во-вторых инлайн не всегда хорошо, поскольку приводит к увеличению кода.

Цитата(Mayk @ 30.6.2005, 00:51)
Это имеет отношение к ООП, так как ООП предоставляет возможность делать языки программирования в которых легко забыть о том, что getX() будет вызыван и не подставлен.

Это незначительно уменьшает скорость вызова метода, и все. Приложения, для которых подобное различие является существенным - это скорее реал-тайм, их и так на асме или С пишут.

Цитата(Mayk @ 30.6.2005, 00:51)
Взять для примера робокот. getX() там НЕ объявлен финальным. Его можно перегрузить, хотя польза от подобной перегрузки весьма сомнительна. Ну я вот не могу придумать зачем отдельно взятому роботу перегружать getX()... (Тем более, что в заблуждение врагов это не вводитsmile)

Дык потому что это никак не повлияет на производительность кота. Ну предположим создатель заменил бы все что можно на финал. Предположим, за счет этого бы был выигран дополнительный фрейм в секунду (в чем я очень сомневаюсь). Но мы бы этого и не заметили, потому что для глаза что 40 что 39 фреймов в секунду - все едино.

Цитата(Mayk @ 30.6.2005, 00:51)
Сиди, гадай как получить, скажем, вес колеса машины: не то Car.getDetailWeight("Wheel1"); не то Car.getGrouppedDetails("Wheels").getSingleDetail(1).weight(), а может колесо вообще деталью не счиатают и надо Car.getWheelWeight().

Подобные вещи решает архитектор проекта, который дает кодеру готовую УМЛ диаграмму где все расписано. Или ты сам продумываешь структуру приложения. Только ты знаешь нужно тебе колесо в дальнейшем или нет, есть ли вообще возможность что понадобится создать класс колеса и вести их учет. Основываясь на этом, ты легко можешь решить какой метод писать.


Цитата(Mayk @ 30.6.2005, 00:51)
3.2) непосредственное написание классов.
Это довольно утомительное занятие писать классы, если эти классы тривиальны и большинство функций в них - это get/setы. Пример - математический вектор. В здравом уме в си никто и не подумает писать getX() для вектора. Максимум - это #define vector_getX(vector) ((vector).x). А в ООП здравый ум так делать не будет.

Писать дольше, зато реюзать легче. А вообще-то в любой ИДЕ есть такая штука как создание класса/поля/метода/итп где ве что надо делать это кликать на ок и вбивать название.


--------------------

PM   Вверх
Mayk
Дата 30.6.2005, 15:09 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


^аВаТаР^ сообщение>>
****


Профиль
Группа: Участник
Сообщений: 2616
Регистрация: 22.5.2005
Где: за границей разум а

Репутация: 2
Всего: 134



Цитата(Domestic @ 30.6.2005, 11:07)
Подобные вещи решает архитектор проекта, который дает кодеру готовую УМЛ диаграмму где все расписано. Или ты сам продумываешь структуру приложения. Только ты знаешь нужно тебе колесо в дальнейшем или нет, есть ли вообще возможность что понадобится создать класс колеса и вести их учет. Основываясь на этом, ты легко можешь решить какой метод писать.

Не все библиотеки написаны мною. В скаченных либах UML диаграмм обычно не наблюдается. Зато наблюдается непонятные имена функций. Напрмимер в QT шной qwidget.h почему есть getWFlags(), если почти все остальные get'ы названы как size(), parent()? Кроме того, при просмтре .hшки возникает вопрос - чем windowState() отличается от getWState()? Оба возвращают uint.


Цитата(Domestic @ 30.6.2005, 11:07)
Дык потому что это никак не повлияет на производительность кота. Ну предположим создатель заменил бы все что можно на финал. Предположим, за счет этого бы был выигран дополнительный фрейм в секунду (в чем я очень сомневаюсь).

Запусти бой между 10 роботами на 1000 раундов и сверни робокот smile А теперь думаем. Сколько раз будет вызываться getX(), getY() за раунд? Много, это очевидно. Умножаем это кол-во на 1000, домножаем на время вызова виртуальной функции. А теперь скажи,
неужели и сейчас выигрыш не виден?
Кстати, скорость компиляции ОО языков меньше чем функциональных: все же компилятору легче распарсить один идентификатор
list_add нежели три list, ->, add. Разумеется, в функциональных языках все идентификаторы записываются в одну хэш таблицу, в то время как в ОО их можно распихать в несколько, но при хорошем хэшировании это будет не страшно и даже не заметно(если интересно, что такое хорошое хэширование, советую посмотреть как хэшируется содержимое PAKов в QuakeForge).


Цитата(Domestic @ 30.6.2005, 11:07)
Во-вторых инлайн не всегда хорошо, поскольку приводит к увеличению кода.

Ну пусть размер файла увеличится даже на 10%. Ну и кого это волнует, если память измеряется мегабайтами? Лично мне всё равно сколько весит екзежник - метр, или метр и сто кб. Меня размеры экзежника не волновали даже на 40 метровом винте. Размер исполяемого файла обычно иного меньше размера всяких .dat файлов. А тебя так волнует размер исполняемого файла? Только честно.

Цитата(Domestic @ 30.6.2005, 11:07)
А вообще-то в любой ИДЕ есть такая штука как создание класса/поля/метода/итп где ве что надо делать это кликать на ок и вбивать название.

Во-первых на это ты уже сам ответил
Цитата(Domestic @ 30.6.2005, 11:07)
речь ведь не о технических средствах

Во-вторых не всякая IDE сделает код для get и set функций. Ну объявятся они в .cpp, но return var; и var=value; всё равно придется писать руками.





--------------------
 Здесь был кролик. Но его убили.
Человеки < кроликов, йа считаю.
PM MAIL WWW ICQ   Вверх
Domestic Cat
Дата 30.6.2005, 17:59 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Экс. модератор
Сообщений: 5452
Регистрация: 3.5.2004
Где: Dallas, US

Репутация: 4
Всего: 172



Цитата(Mayk @ 30.6.2005, 06:09)
Запусти бой между 10 роботами на 1000 раундов и сверни робокот smile А теперь думаем. Сколько раз будет вызываться getX(), getY() за раунд? Много, это очевидно. Умножаем это кол-во на 1000, домножаем на время вызова виртуальной функции. А теперь скажи,
неужели и сейчас выигрыш не виден?

Ну понятно, что такой метод будет вызываться медленнее, ну будет проигрыш по времени в данном случае на, скажем, секунду. Это на что-то влияет?
Плата за вызов метода компенсируется полиморфизмом и наследованием, программист должен выбрать: то ли пользоваться этим и проиграть на скорости вызова метода, то ли не пользоваться. В большинстве приложений проигрыш по скорости ни на что не влияет, тогда и ОО язык и имеет преимущество.

Цитата(Mayk @ 30.6.2005, 06:09)
Кстати, скорость компиляции ОО языков меньше чем функциональных: все же компилятору легче распарсить один идентификатор
list_add нежели три list, ->, add. Разумеется, в функциональных языках все идентификаторы записываются в одну хэш таблицу, в то время как в ОО их можно распихать в несколько, но при хорошем хэшировании это будет не страшно и даже не заметно(если интересно, что такое хорошое хэширование, советую посмотреть как хэшируется содержимое PAKов в QuakeForge).

Опять, скорость компиляции при существующем железе будет практически неотличима. Я не могу на глаз отличить скорость gcc на Маке и jikes под виндой.

Цитата(Mayk @ 30.6.2005, 06:09)

Ну пусть размер файла увеличится даже на 10%. Ну и кого это волнует, если память измеряется мегабайтами? Лично мне всё равно сколько весит екзежник - метр, или метр и сто кб. Меня размеры экзежника не волновали даже на 40 метровом винте. Размер исполяемого файла обычно иного меньше размера всяких .dat файлов. А тебя так волнует размер исполняемого файла? Только честно.

Ты ж робокота юзаешь smile Например, размер класс файла получается меньше, чем соответствующего С файла.
Вообще размер исполняемого файла тоже по идее должен влиять на скорость исполнения, ведь он должен быть загружен в память?

Цитата(Mayk @ 30.6.2005, 06:09)
Во-вторых не всякая IDE сделает код для get и set функций. Ну объявятся они в .cpp, но return var; и var=value; всё равно придется писать руками.

Хорошо, можно написать ИДЕ которая будет из имени переменной и ее типа вставлять также эти ретурны и и var=value...

Когда что-то вводится в язык, в результате приходится больше писать, но ведь есть и какой-то выигрыш.
Возьмем васик - помнится в васике "подпрограммы" писались через указание заведомо большого номера строки, в конце стоял goto. В процедурных языках для таких целей используется функция или процедура. Писать больше (типы, название, вызов), зато такую процедуру можно реюзать много раз, тогда как бейсиковские "процедуры" были одноразовыми (тк гото всегда возвращал на одну и ту же строку).
Первоначально программы писались в один файл. Потом оказалось что при большом размере программы работать с ней становится невозможно, и появились модули. Модуль нужно писать - создавать файл, называть, писать хедер, труда больше но и выигрыш очевиден.
С ООП то же самое, ты пишешь больше кода, но это облегчает жизнь впоследствии. Если не делать гет/сет методы, то чтобы определить, кто и когда изменил переменную (паблик) нужно отрудиться. Если же указан даже "пустой" сет метод var=value, то чтобы определить кто вызвал метод, достаточно дописать туда две строки...

ПС Если на то пошло, то например в Intellij IDEA нажатием 2-3 кнопок можно создавать комменты, блоки (циклы, трай-кетчи, ифы, итп), методы, переходить к определению любого метода или переменной, просматривать сорсы любого класса включая библиотечные, и миллион разных вещей - и все это с 2-3 кнопками. По скорости написания любой процедурный язык обгонишь, как бы мало там не надо было писать. Потому я и говорю о том, что тех.средства не показатель.


--------------------

PM   Вверх
Mayk
Дата 30.6.2005, 19:31 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


^аВаТаР^ сообщение>>
****


Профиль
Группа: Участник
Сообщений: 2616
Регистрация: 22.5.2005
Где: за границей разум а

Репутация: 2
Всего: 134



Цитата(Domestic @ 30.6.2005, 18:59)

Ну понятно, что такой метод будет вызываться медленнее, ну будет проигрыш по времени в данном случае на, скажем, секунду. Это на что-то влияет?

Да. Я так тестирую робота smile Если он будет тестроваться за 59 секунд, а не за минуту, то я буду рад.

Цитата(Domestic @ 30.6.2005, 18:59)
Опять, скорость компиляции при существующем железе будет практически неотличима. Я не могу на глаз отличить скорость gcc на Маке и jikes под виндой.

Gaim компилировался быстрее, чем sim. Хотя первый в архиве весил 5 метров, а второй 3. Но gaim написан на си, а сам на плюсах. Разумеется здесь еще очень сильно тормозят шаблоны, но gaim всё равно компилируется быстрее при большем весе smile Как, впрочем, и все си программы... Во-всяком случае не могу вспомнить прогу на сях, которая бы компилировалась столь же долго, как и аналогичная по объему и/или функциональности прога на плюсах.

Цитата(Domestic @ 30.6.2005, 18:59)
Например, размер класс файла получается меньше, чем соответствующего С файла.

Некорректное сравнение. .с - исходник. .class - откомпилированный исходник. Или ты про .java? Ну... Я вот сделал один в один.
364 байта против 364ех smile
Код

package sample;
import robocode.*;
public class MyFirstRobot extends Robot
{
    public void run() {
        while (true) {
            ahead(100);
            turnGunRight(360);
            back(100);
            turnGunRight(360);
        }
    }
    public void onScannedRobot(ScannedRobotEvent e) {
        fire(1);
    }
    public void onHitByBullet(HitByBulletEvent e) {
        turnLeft(90 - e.getBearing());
    }
}

Код

#include"robocode.h"
static robot r = {run, fire, onHit};
static void run()
{
    while(1){
        ahead(&r,100);
        turnGunRight(&r,360);
        back(&r,100);
        turnGunRight(&r,360);
    }
}
static void fire(ScannedRobotEvent* e){
    fire(&r,1);
}
static void onHit(HitByBulletEvent* e){
    turnLeft(&r,90 - e->getBearing());
}
robot* EXPORT init()
{
    return &r;
}


Цитата(Domestic @ 30.6.2005, 18:59)
Вообще размер исполняемого файла тоже по идее должен влиять на скорость исполнения, ведь он должен быть загружен в память?

Должен-то конечно должен, но сотня килобайт не большой объем для винта не сыплющего бэды. Кроме того у меня notepad.exe загружается когда за полcекунды, а когда и за секунду. Слишком много второстепенных факторов делают загрузку нескольких дополнтельных килобайт абсолютно незаметными. Пусть лучше программа загрузится не за 1,00 сек, а за 1,01 сек, но будет работать быстрее.
Цитата(Domestic @ 30.6.2005, 18:59)
Хорошо, можно написать ИДЕ которая будет из имени переменной и ее типа вставлять также эти ретурны и и var=value...

А можно в очередной раз обратиться за помощью к препроцессору. Он есть во всех сях. А ИДЕ не все любят. Например, я люблю vim+ctags+пару скриптов для создания классов и заголовочных файлов.
Код

#define __Property(var_t, __variable, get_func, set_func) \
private: var_t __variable; \
public: var_t get_func() const{return __variable;}
public: void set_func(var_t __new_value){__variable=__new_value;}
class Wheel{
__Property(double, m_weight, weight, setWeight)
};

Цитата(Domestic @ 30.6.2005, 18:59)
Возьмем васик - помнится в васике "подпрограммы" писались через указание заведомо большого номера строки, в конце стоял goto.

В конце стоял RETURN. А вызывалась "функция" посредством GO SUB. При некотором опыте код GO SUB 5000 был довольно читаем.
Например можно было разместить там чтение клавиши q/a/o/p/space.
Помню, у меня на спеки последние строки были
9998 STOP //брякпоинт
9999 RANDOMIZE USR 15616: REM: SAVE "program" //запись на дискету


Цитата(Domestic @ 30.6.2005, 18:59)
Когда что-то вводится в язык, в результате приходится больше писать, но ведь есть и какой-то выигрыш.

Итак, делаем вывод. ООП хорош для больших проектов, чьи системные требования относительно высоки. Теоретически можно написать столь же быстрое приложение на плюсах, как и на сях. Но реализация того же сишного быстродействия потребует большего времени, нежели на чистом си. Реюзабельный код можно писать на любом языке. ООП встаёт во всей своей красе при работе с большим кол-вом абстрактных данных(пример - построение GUI), в то время как при отстутствии абстракции рулит функционалка.


--------------------
 Здесь был кролик. Но его убили.
Человеки < кроликов, йа считаю.
PM MAIL WWW ICQ   Вверх
Domestic Cat
Дата 30.6.2005, 19:39 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Экс. модератор
Сообщений: 5452
Регистрация: 3.5.2004
Где: Dallas, US

Репутация: 4
Всего: 172



Цитата(Mayk @ 30.6.2005, 10:31)
Некорректное сравнение. .с - исходник. .class - откомпилированный исходник. Или ты про .java? Ну... Я вот сделал один в один.
364 байта против 364ех smile

Вообще-то я говорил про исполняемые файлы. Или ты имел в виду сорсы?

Цитата(Mayk @ 30.6.2005, 10:31)
В конце стоял RETURN. А вызывалась "функция" посредством GO SUB. При некотором опыте код GO SUB 5000 был довольно читаем.
Например можно было разместить там чтение клавиши q/a/o/p/space.
Помню, у меня на спеки последние строки были
9998 STOP //брякпоинт
9999 RANDOMIZE USR 15616: REM: SAVE "program" //запись на дискету

Забыл совсем smile

Цитата(Mayk @ 30.6.2005, 10:31)
в то время как при отстутствии абстракции рулит функционалка.

С предыдущим я согласен, но вот не пойму что значит количество абстрактных данных? Данные в любом случае - абстракция.



--------------------

PM   Вверх
Mayk
Дата 30.6.2005, 22:00 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


^аВаТаР^ сообщение>>
****


Профиль
Группа: Участник
Сообщений: 2616
Регистрация: 22.5.2005
Где: за границей разум а

Репутация: 2
Всего: 134



Цитата(Domestic @ 30.6.2005, 20:39)
Вообще-то я говорил про исполняемые файлы. Или ты имел в виду сорсы?

Я имел в виду сорсы. А сравнивать виртуальную машину и реальную не совсем верно. Разве в .class'ы линкуются статичные либы?

Цитата(Domestic @ 30.6.2005, 20:39)
предыдущим я согласен, но вот не пойму что значит количество абстрактных данных?

Не совсем точно выразился. Переформулирую подробней:
В UI есть лабелы, кнопки, поля для редактирования текста, картинки, панели, меню, тулбары и так далее. И со всеми с ними можно выполнять множество одинаковых действий, как то их активирование, кликание на них, сброс в них(drop), изменение enable, показ, прятание, перемещение, изменение размера. Здесь ООП с виртуальным наследованием подойдет гораздо лучше. Во всяком случае не хочется писать что-нить типа того:
Код

memcpy(link_vtable, text_vtable, sizeof(*link_vtable));
link_vtable->clicked=link_clicked()
link_vtable->typeId=TYPE_LINK;

Плюснутое class Link : public Text{ void clicked(); } гораздо локаничнее. Сравнить:
Код

MainWindow : Dialog() {
    addChild(new Button(this,"quit"));
}

void MainWindow::hideAllButtons()
{
    for (Widget* iter = child; iter; iter=iter->next){
        Button* btn = dynamic_cast<Button*>(iter);
        if(btn) btn->hide();
    }
}

и
Код

typedef struct mainwindow_s{
    union{
    widget_t widget; 
    dialogwindow_t dialog;
    };
}mainwindow_t;

#define CREATE_WIDGET NULL

dialogwindow_t dialog_new(dialogwindow_t* dlg=CREATE_WIDGET);

mainwindow_t* mainwindow_new(mainwindow_t* win=CREATE_WIDGET)
{
    if(win==0){
        win = calloc(1,sizeof(*win));
        dialog_new(&win->dialog);
    }    
    win->widget.vtable = mainwindow_vtable;
    add_child((widget_t*)button_new(CREATE_WIDGET, win, "hello"))
    return win;
}

void mainwindow_hide_all_buttons(mainwindow_t* w)
{
    for (widget_t* iter = w->child; iter; iter=iter->next){
        if(iter->vtable->typeinfo == TYPE_BUTTON)
              iter->vtable->hide(iter); 
    }
}

Обрати внимание на преобразования типа в вызове add_child. Это напрягает. Ведь в функционалке нет преобразования типов, здесь отсутствует абстракция типов: нет отвлечния от действительного типа, есть лишь преобразования типа вручную.
И это преобразование потребуется в каждом вызове add_child, remove_child, is_child_exist, set_parent, при каждом обращении к виртуальной функции. В GUI много абстракции. По сути всё GUI - абстракция.



--------------------
 Здесь был кролик. Но его убили.
Человеки < кроликов, йа считаю.
PM MAIL WWW ICQ   Вверх
Domestic Cat
Дата 1.7.2005, 07:25 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Экс. модератор
Сообщений: 5452
Регистрация: 3.5.2004
Где: Dallas, US

Репутация: 4
Всего: 172



Цитата(Mayk @ 30.6.2005, 13:00)
Обрати внимание на преобразования типа в вызове add_child. Это напрягает. Ведь в функционалке нет преобразования типов, здесь отсутствует абстракция типов: нет отвлечния от действительного типа, есть лишь преобразования типа вручную.
И это преобразование потребуется в каждом вызове add_child, remove_child, is_child_exist, set_parent, при каждом обращении к виртуальной функции. В GUI много абстракции. По сути всё GUI - абстракция.

Разве такая ситуация редка или специфична для гуя? По-моему, нет.


--------------------

PM   Вверх
Mayk
Дата 1.7.2005, 15:46 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


^аВаТаР^ сообщение>>
****


Профиль
Группа: Участник
Сообщений: 2616
Регистрация: 22.5.2005
Где: за границей разум а

Репутация: 2
Всего: 134



Цитата(Domestic @ 1.7.2005, 08:25)
специфична для гуя

ГУЙ был взят в качестве примера.


--------------------
 Здесь был кролик. Но его убили.
Человеки < кроликов, йа считаю.
PM MAIL WWW ICQ   Вверх
Страницы: (3) Все [1] 2 3 
Ответ в темуСоздание новой темы Создание опроса
Правила ведения Религиозных войн
Smartov
1. Уважайте собеседника
2. Собеседник != враг
3. Старайтесь воздерживаться от тем вида "Windows Rulez" или "Linux Rulez"

С уважением, Smartov.

 
0 Пользователей читают эту тему (0 Гостей и 0 Скрытых Пользователей)
0 Пользователей:
« Предыдущая тема | Религиозные войны | Следующая тема »


 




[ Время генерации скрипта: 0.0728 ]   [ Использовано запросов: 22 ]   [ GZIP включён ]


Реклама на сайте     Информационное спонсорство

 
По вопросам размещения рекламы пишите на vladimir(sobaka)vingrad.ru
Отказ от ответственности     Powered by Invision Power Board(R) 1.3 © 2003  IPS, Inc.