LINUX.ORG.RU

В чём суть ООП?


3

5

С точки зрения манеры проектирования, а не особенностей реализации С++ там CLOS. Вот например я использую определения классов и даже иногда наследование как узнать пишу ли я в ООП стиле?

★★★★★

Ответ на: комментарий от tailgunner

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

нет, не похоже

jtootf ★★★★★ ()
Ответ на: комментарий от drBatty

Давай вернёмся к iostream, разве для них ООП нужно? Что, fopen/fread/fwrite/fclose/fprintf/fscanf недостаточно?

Мы можем переопределить operator<<,>> Что может быть полезно.

Dudraug ★★★★★ ()
Ответ на: комментарий от tailgunner

Но статья умиляет: «duck typing is dynamic» и потом «Template, or generic functions or methods apply the duck test in a static typing context». Похоже, не только в русской Вики пишут маразм о CS.

tailgunner ★★★★★ ()
Ответ на: комментарий от Dudraug

Виртуальные деструкторы тоже особо с ООП не связаны. Точнее они связаны с реализацией ООП в С++, но никак не парадигмой ООП.

безусловно. Это кривизна C++, что в нём надо делать виртуальные деструкторы. По уму они должны наследоваться, а они - не наследуются.

drBatty ★★ ()
Ответ на: комментарий от Dudraug

Мы можем переопределить operator<<,>> Что может быть полезно.

может... IRL это не нужно ИМХО.

drBatty ★★ ()
Ответ на: комментарий от tailgunner

Но статья умиляет: «duck typing is dynamic» и потом «Template, or generic functions or methods apply the duck test in a static typing context». Похоже, не только в русской Вики пишут маразм о CS.

потому-что в C++ нет утиной типизации. И это - хорошо.

drBatty ★★ ()
Ответ на: комментарий от drBatty

тогда производный деструктор вызовется, а вот деструктор базового класса - нет

Завязывай с веществами:

foo.cc:

#include <iostream>

struct A
{
	~A() { std::cout << "~A()" << std::endl; }
};

struct B : A
{
	virtual ~B() { std::cout << "~B()" << std::endl; }
};

struct C : B
{
	~C() { std::cout << "~C()" << std::endl; }
};

int main()
{
	B* x = new C;
	delete x;
}
$ g++ -o foo foo.cc
$ ./foo 
~C()
~B()
~A()

Begemoth ★★★★★ ()
Ответ на: комментарий от drBatty

я знаю, что синтаксис это позволяет. Синтаксис вообще многое позволяет, но тривиальные структуры, которые не предполагают полиморфизма и частичной инкапсуляции ИМХО следует называть struct. Если тебе нужно структуру полностью скрыть - её можно полностью скрыть. А если часть методов у тебя наружу, то это ИМХО уже класс, который годен для наследования (по умолчанию).

facepalm.mkv

Dudraug ★★★★★ ()
Ответ на: комментарий от drBatty

C++ класс с открытыми функциями-членами не является интерфейсом?

Является. Но функция друг. Или функция не член и не друг, но принимающая на вход параметром класс, тоже является интерфейсом.

Dudraug ★★★★★ ()
Ответ на: комментарий от drBatty

может... IRL это не нужно ИМХО.

Не говори за всех. Мне вот это было РЕАЛЬНО нужно.

Dudraug ★★★★★ ()
Ответ на: комментарий от Begemoth

Завязывай с веществами:

using namespace std;

#include <iostream>
#include <string>



class Foo {
public:
    ~Foo()
	{
		cout << "~Foo()" << endl;
	}
};

class Bar : public Foo {
private:
    int* numbers;
public:
    Bar() : numbers(new int[17]) {
	}
    ~Bar()
	{
		cout << "~Bar()" << endl;
	}
};

int main()
{
	Bar* b = new Bar;
	delete b; // Вызывает Bar::~Bar()
	Foo* f = new Bar;
	delete f; // Ой! Вызывается Foo::Foo()! 
}

(C)Джефф Элджер

drBatty ★★ ()
Ответ на: комментарий от Dudraug

Является. Но функция друг. Или функция не член и не друг, но принимающая на вход параметром класс, тоже является интерфейсом.

ну и?

drBatty ★★ ()
Ответ на: комментарий от Dudraug

Не говори за всех. Мне вот это было РЕАЛЬНО нужно.

так, что если-бы не было iostream, ты-бы удавился? т.е. printf(3) ну никак?

drBatty ★★ ()
Ответ на: комментарий от drBatty

Я знаю, но зачем тебе указатель на Foo, а не на Bar в компоненте контролиующем время жизни этого объекта?

Begemoth ★★★★★ ()
Ответ на: комментарий от Dudraug

Мы можем переопределить operator<<,>> Что может быть полезно.

Как используя оператор «>>» прочитать один байт?

red_eyed_peguin ()
Ответ на: комментарий от drBatty

Ну и все, выше ты сказал, что a->print() более логичен с точки зрения ООП, но это не так.

Dudraug ★★★★★ ()
Ответ на: комментарий от drBatty

так, что если-бы не было iostream, ты-бы удавился? т.е. printf(3) ну никак?

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

Dudraug ★★★★★ ()
Ответ на: комментарий от red_eyed_peguin

Как используя оператор «>>» прочитать один байт?

А как в printf добавить поддержку своего типа?

Begemoth ★★★★★ ()
Ответ на: комментарий от red_eyed_peguin

Как используя оператор «>>» прочитать один байт?

В смысле? Есть же метод get(). Я о другом говорил же

Dudraug ★★★★★ ()
Ответ на: комментарий от Begemoth

Я знаю, но зачем тебе указатель на Foo, а не на Bar в компоненте контролиующем время жизни этого объекта?

например есть готовая коллекция, которая умеет удалять эл-ты. Она работает с Foo. Но не сможет работать с новым Bar наследником Foo, т.к. ~Bar() не будет вызываться.

drBatty ★★ ()
Ответ на: комментарий от Begemoth

И, кстати, вот это «тогда производный деструктор вызовется, а вот деструктор базового класса - нет» будешь обосновывать?

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

drBatty ★★ ()
Ответ на: комментарий от slackwarrior

Он есть - ты теперь вдоль сделаешь?

зачем? ну есть и есть, мне он не мешает. Вот если-бы не было...

drBatty ★★ ()
Ответ на: комментарий от Dudraug

Ну и все, выше ты сказал, что a->print() более логичен с точки зрения ООП, но это не так.

по твоему, функция-друг логична с т.з. ООП? А мне кажется, что это костыль (с т.з. ООП)

drBatty ★★ ()
Ответ на: комментарий от Dudraug

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

В некоторых случаях оптимальный вид транспорта - самокат. Это не говорит о том, что самокат нужен 146% населения. Мне не нужен.

drBatty ★★ ()
Ответ на: комментарий от Begemoth

А как в printf добавить поддержку своего типа?

man vprintf

drBatty ★★ ()
Ответ на: комментарий от drBatty

по твоему, функция-друг логична с т.з. ООП? А мне кажется, что это костыль (с т.з. ООП)

Вообще-то логичнее и не друг и не член, если такое возможно. У тебя мозг пропитан существующими реализациями. Сама концепция ООП базируется на понятиях объекта и интерфейса. Функция-член - это реализация к которой все привыкли.

Dudraug ★★★★★ ()
Ответ на: комментарий от drBatty

В некоторых случаях оптимальный вид транспорта - самокат. Это не говорит о том, что самокат нужен 146% населения. Мне не нужен.

Выше ты сказал, что в IRL переопределение >> не нужно, вообще. Но оно нужно.

Dudraug ★★★★★ ()
Ответ на: комментарий от Dudraug

Вообще-то логичнее и не друг и не член, если такое возможно.

в С++ невозможно.

Сама концепция ООП базируется на понятиях объекта и интерфейса. Функция-член - это реализация к которой все привыкли.

угу. А что, мне нравится

drBatty ★★ ()
Ответ на: комментарий от Dudraug

Выше ты сказал, что в IRL переопределение >> не нужно, вообще. Но оно нужно.

для iostream? я не первый, кто это сказал.

drBatty ★★ ()
Ответ на: комментарий от drBatty

в С++ невозможно.

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

Кончай уже чушь пороть.

Dudraug ★★★★★ ()
Ответ на: комментарий от drBatty

для iostream? я не первый, кто это сказал.

Да какая разница? Ты не прав.

Dudraug ★★★★★ ()
Ответ на: комментарий от Begemoth

А как в printf добавить поддержку своего типа?

info libc -> 12.13 Customizing printf. Не спорю, что это гнутое расширение. iostream — фейловый концепт плюсовки, это признают все. Пока в iostream'ах запишешь «printf(«%.2f», 1./2)», успеешь забыть, нафига ты это делаешь.

red_eyed_peguin ()
Ответ на: комментарий от Dudraug

Есть же метод get(). Я о другом говорил же

Ты говорил о том, что можно переопределить операторы <<,>> для объектов. Только почему-то забыл, что это крайне уныло дружит с динамическим полиморфизмом и если для базового класса такой оператор не определен как вызов виртуального метода объекта (ostream& operator<<(ostream &out, const Foo &foo) {return foo.out(out);}), то вся твоя стройная концепция пойдет коту под хвост.

red_eyed_peguin ()
Ответ на: комментарий от red_eyed_peguin

Ну я говорил про переопределение <<,>> для потоков ввода вывода. Это позволяет изменить их поведение. Когда это нужно. Может и не особо вписывается в полиморфизм, но свою задачу выполняет. И да, переопределением надо пользоваться с умом. Инструмент есть, но он - острая бритва. Никто не говорил, что надо бездумно переопределять операторы направо и налево. Нет!

Dudraug ★★★★★ ()
Ответ на: комментарий от red_eyed_peguin

Оба решения далеки от идеала, можно сойтись на этом.

Dudraug ★★★★★ ()
Ответ на: комментарий от drBatty

например есть готовая коллекция, которая умеет удалять эл-ты. Она работает с Foo.

А из извлечении элемента из коллекции ты будешь приводить тип к Bar и затем работать с ним? То что ты описываешь представляется странной стратегией владения.

А мне надо и то и другое, что-бы старый код нормально работал без изменений.

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

Begemoth ★★★★★ ()
Ответ на: комментарий от Dudraug

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

через операторы так делается только из кривизны синтаксиса. Ты не сможешь перезагрузить X * Y для класса Y методом этого Y. Только функцией-другом.

То есть если ты создаешь новый метод, а для его работы нужны или публичные члены, или его работу можно организовать через публичные члены или другие подобные методы, то лучше не делать его ни членом, ни функцией другом. Ну и да Gobject же! Там нет функций членов.

Кончай уже чушь пороть.

ага. Не знаю как в Go, но в C++ кроме методов класса и костылей-статических_функций какие ещё способы реализации ООП?

drBatty ★★ ()
Ответ на: комментарий от Dudraug

Оба решения далеки от идеала,

4.2

Форматная строка *printf - DSL для преобразования двоичных данных в их текстовое представление. Чуть более чем все широко используемые компиляторы проверяют передаваемые параметры на соответствие формату.

Удобство этого решения таково, что даже в жабу добавили printf, спустя добрый десяток лет.

LamerOk ★★★★★ ()
Ответ на: комментарий от Dudraug

Да какая разница? Ты не прав.

ну я с самого начала писал, что ИМХО неправильно юзать cout << x. Это не только моё ИМХО. может и неправильное. Я не запрещаю, во всяк. случае.

drBatty ★★ ()
Ответ на: комментарий от LamerOk

Удобство этого решения таково, что даже в жабу добавили printf, спустя добрый десяток лет.

да что там говорить. Почти любой язык «из коробки» предоставляет в том или ином виде форматный вывод.

theNamelessOne ★★★★★ ()

В чём суть ООП?

о перегрузке пробела уже было?

ukr_unix_user ★★★★ ()
Ответ на: комментарий от LamerOk

Удобство этого решения таково...

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

Скорее дело в том, что сложно сделать форматирование правильно (и удобно), но это отнюдь не значит, что нельзя.

Похожая ситуация с регэспами - удобные парсеры есть не везде.

anonymous ()
Ответ на: комментарий от Begemoth

А из извлечении элемента из коллекции ты будешь приводить тип к Bar и затем работать с ним? То что ты описываешь представляется странной стратегией владения.

ну что поделать...

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

старый тип это возможно элемент коллекции. Мне нравится эта коллекция, но не хватает возможностей эл-тов. Почему их(возможности) нельзя расширить? Не всё-ли равно коллекции, что там будут делать её эл-ты?

drBatty ★★ ()
Ответ на: комментарий от LamerOk

Чуть более чем все широко используемые компиляторы проверяют передаваемые параметры на соответствие формату.

только встроенные типы проверяет, и кидает warning.

drBatty ★★ ()
Ответ на: комментарий от LamerOk

Чуть более чем все широко используемые компиляторы проверяют передаваемые параметры на соответствие формату.

В случае с printf это очень хорошо, но для какого-нибудь своего подобного DSL, компилятор ничем не поможет, и выхода для С++: либо делать интерфейс на перегруженных операторах как в Boost.Format, либо на шаблонах с произвольным числом параметров (а они поддерживаются не всеми компиляторами, в частности VC++11).

Begemoth ★★★★★ ()
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.