Re: И все-таки квадрат это прямоугольник
От: last_hardcoder  
Дата: 07.03.07 08:49
Оценка:
Здравствуйте, igna, Вы писали:

I>
I>class Rectangle {
I>    int width, height;

I>    public Rectangle(int width, int height) {
I>        this.width = width;
I>        this.height = height;
I>    }
I>    public int Width() {
I>        return width;
I>    }
I>    public int Height() {
I>        return height;
I>    }
I>}

I>class Square extends Rectangle {
I>    public Square(int side) {
I>        super(side, side);
I>    }
I>}
I>


Это решение соответствует минимуму кода и максимуму памяти, занимаемой объектом. Оно не является идеальным для 100% случаев применения.
Re[2]: И все-таки квадрат это прямоугольник
От: igna Россия  
Дата: 07.03.07 08:57
Оценка:
Здравствуйте, last_hardcoder, Вы писали:

_>Это решение соответствует минимуму кода и максимуму памяти, занимаемой объектом. Оно не является идеальным для 100% случаев применения.


Конечно нет, но оно возможно и корректно. Вопреки распространенному мнению, что квадрат якобы вообще никогда нельзя производить от прямоугольника.
Re: И все-таки квадрат это прямоугольник
От: elmal  
Дата: 07.03.07 09:23
Оценка:
Здравствуйте, igna, Вы писали:

А почему рассматриваете только простейшие случаи наследования? Если мне не изменяет память (из школьного курса математики), то квадрат это правильный многогранник (терминологию могу забыть уже), у которого число граней равно 4. А прямоугольник это более общий случай многогранника. И иерархия наследования для квадрата будет "Фигура <- Многогранник <- правильный многогранник <- квадрат (хотя его можно не выделять)". Плюс кваррат является четырехугольником (то есть множественное наследование). А для прямоугольника — "Фигура <- Многогранник <- четырехугольник <- прямоугольник".

Это естественно только одна из возможных иерархий наследования. Можно сделать посложнее, можно попроще. А степень сложности будет определяться требованиями к поддержке фигур, в случае, если изначально нужно поддерживать только прямоугольники и квадраты, то наследовать квадрат от прямоугольника допустимо. Также степень сложности будет определяться методами классов, в случае, если от этих фигур требуется только рисоваться, то лучше вообще определить, что и то, и другое является фигурами (абстрактный класс) и не мучиться с наследованием. А если потребуется там площади, периметры, диагонали считать — то иерархию придется пересмотреть. Главное в иерархиях наследования, чтобы они упрощали все, а не усложняли плюс убирали дублирующийся код. XP рулит, заранее все усложнять не очень хорошо . Все равно заранее всего не предусмотреть.
Re[3]: И все-таки квадрат это прямоугольник
От: last_hardcoder  
Дата: 07.03.07 09:43
Оценка:
Здравствуйте, igna, Вы писали:

I>Конечно нет, но оно возможно и корректно. Вопреки распространенному мнению, что квадрат якобы вообще никогда нельзя производить от прямоугольника.


Если отвлечся от конкретики фигур, то получается, что частные случаи нельзя выражать через общие? Ну это бред какой-то. И частные через общие можно выражать, и развивать частные до общих, и независимо реализовывать и то и другое. Вопрос лишь в ресурсах, которые тратятся в каждом случае.
Re[2]: И все-таки квадрат это прямоугольник
От: last_hardcoder  
Дата: 07.03.07 10:48
Оценка:
Здравствуйте, Tilir, Вы писали:

T>Ох уж мне эти java-developer'ы... Ясное дело, Мейерса вы не читали. А между прочим, в книге "Эффективное использование C++" есть целый раздел, посвящённый тому, почему (в рамках философии C++) квадрат нельзя наследовать от прямоугольника. Коротко говоря, для него не выполняется LSP. Очень советую ознакомится. Если лень читать всю книжку, то подскажу: см. правило №35.


Там сказано, что нельзя публично наследовать. А приватно то что мешает?
Re[3]: И все-таки квадрат это прямоугольник
От: FDSC Россия consp11.github.io блог
Дата: 07.03.07 11:11
Оценка:
Здравствуйте, Pavel Dvorkin, Вы писали:

PD>Здравствуйте, Big_Urri, Вы писали:


B_U>>А еще, как квадрат, так и прямоугольник можно задавать длиной диагонали и углом между ними. В этом случае проблем с наследованием и изменяемостью не возникает, поведение фигур полностью идентично. Height и Width будут вычисляемые. Но есть еще ромб.


PD>Только не ромб! Не надо ромбов! Никаких ромбов не надо! Дискуссию с участием еще и ромба сервер не выдержит!


Предлагаю наследовать вместо ромба токосъёмник от электропоездов

PD>P.S. Как много у программистов свободного времени


Мда... только вот потом все почему-то жалуются на то, что заставляют работать сверхурочно
Re[8]: И все-таки квадрат это прямоугольник
От: . Великобритания  
Дата: 07.03.07 11:35
Оценка:
Tilir wrote:

> // private: const Rectangle GetCopyX(double n){}; // чтобы её не дай Б-же не вызвали

Ну вот и меня соблазнили в флейм ввязаться!
Почему не бы вызвать? Пусть вызывают, вернётся нормальный прямоугольник, полученный растягиванием стороны квадрата.

По моему главное при наследовании down-casting. Т.е. если мы имеем
class Rectangle;
class Square : Rectange;

то всё ок.
Square *sq = new Square(5);
assert(sq.GetWidth()*4 == sq.GetPerimeter());
Rectange *rect = sq;
assert((rect.GetWidth()+rect.GetHeight())*2 == rect.GetPerimeter());

Если же наследоваться наоборот
class Square;
class Rectangle : Square;

, то получаются квадраты со сторонами 3*4 — гадость!
Rectangle *rect = new Rectangle(3,4);
Square *sq = rect;
assert(sq.GetWidth()*4 == sq.GetPerimeter());//Бабах!

Т.е. идея такова, что экземлпяры наследника должны вести себя точно также, как экземпляры базы.
Posted via RSDN NNTP Server 2.0
но это не зря, хотя, может быть, невзначай
гÅрмония мира не знает границ — сейчас мы будем пить чай
Re[4]: И все-таки квадрат это прямоугольник
От: igna Россия  
Дата: 07.03.07 11:50
Оценка:
Здравствуйте, last_hardcoder, Вы писали:

_>Если отвлечся от конкретики фигур, то получается, что частные случаи нельзя выражать через общие? Ну это бред какой-то. И частные через общие можно выражать, и развивать частные до общих, и независимо реализовывать и то и другое. Вопрос лишь в ресурсах, которые тратятся в каждом случае.


Ну открой тему с названием вроде "Можно без неприятностей открыто наследовать прямоугольник от квадрата" и одевай каску.
Re[3]: И все-таки квадрат это прямоугольник
От: igna Россия  
Дата: 07.03.07 11:56
Оценка:
Здравствуйте, last_hardcoder, Вы писали:

_>Там сказано, что нельзя публично наследовать. А приватно то что мешает?


Но ведь это форум "Философия программирования", а не "C/C++". Я думаю, в этом форуме "наследование" означает "открытое наследование".
Re[4]: И все-таки квадрат это прямоугольник
От: last_hardcoder  
Дата: 07.03.07 13:58
Оценка:
Здравствуйте, igna, Вы писали:

I>Но ведь это форум "Философия программирования", а не "C/C++". Я думаю, в этом форуме "наследование" означает "открытое наследование".


Бедные не "C/C++" программисты :'( Ну тогда всё правильно, Либо SetWidth должен отсутствовать (что существенно сужает область применения и крайне нежелательно, т.к может стать препядствием расширения системы в будущем, даже если на текущем этапе это не нужно). Либо наследовать нельзя и нужно создавать обёртку, прячущую SetWidth, отличным от наследования способом.
Re[9]: И все-таки квадрат это прямоугольник
От: Tilir Россия http://tilir.livejournal.com
Дата: 07.03.07 14:15
Оценка:
Здравствуйте, ., Вы писали:

.>, то получаются квадраты со сторонами 3*4 — гадость!

Rectangle *rect = new Rectangle(3,4);
Square *sq = rect;
assert(sq.GetWidth()*4 == sq.GetPerimeter());//Бабах!

.>Т.е. идея такова, что экземлпяры наследника должны вести себя точно также, как экземпляры базы.

Вот здесь есть моя реализация:
http://www.rsdn.ru/Forum/Message.aspx?mid=2395831&amp;only=1
Автор: Tilir
Дата: 06.03.07


Она в данном случае не даст бабаха, поскольку виртуальная GetWidth (её там напрямую нет, но легко доопределить) для прямоугольника будет возвращать m_Width, а для квадрата m_Len.

Вообще по здравому размышлению, мне до сих пор очень нравится этот код — я так и не смог придумать ситуации, когда бы он привёл к откровенно плохим результатам. Не нужны даже const-модификаторы, а LSP выполняется, поскольку "Все стороны равны" у моего квадрата вырождается в "m_Len==m_Len", что выполняется и для прямоугольника. И побочных эффектов http://www.rsdn.ru/Forum/Message.aspx?mid=2396945&amp;only=1
Автор: Tilir
Дата: 07.03.07
он не вызывает. И по памяти оптимален — зачем квадрату два закрытых члена для длины и ширины? Ему и одного хватит.
А что? Прямоугольник — это на самом деле квадрат, только у него стороны разные.
Re[10]: И все-таки квадрат это прямоугольник
От: . Великобритания  
Дата: 07.03.07 14:41
Оценка:
Tilir wrote:

> А что? Прямоугольник — это на самом деле квадрат, только у него стороны

> разные.
Нет, представь себе, что у тебя есть функция, на вход берущая квадраты.
Она вполне имеет право ожидать, что квадраты квадратные и ничего не знать о существовании прямоугольников.
Так как у тебя от квадрата наследуется прямоугольник, ты можешь получить косвенно вызов "functionForSquaresOnly(new
Rectangle(3,4))"
И функция будет удивлена, обнаружив очень странные свойства у переданного ей квадарата, как то что вдруг периметр стал
каким-то неправильным, например не выполняется "square.getWidth()*4==square.getPerimeter()" и т.п.
Posted via RSDN NNTP Server 2.0
но это не зря, хотя, может быть, невзначай
гÅрмония мира не знает границ — сейчас мы будем пить чай
Re[10]: И все-таки квадрат это прямоугольник
От: deniok Россия  
Дата: 07.03.07 14:42
Оценка: +1 :))) :)
Здравствуйте, Tilir, Вы писали:

T>А что? Прямоугольник — это на самом деле квадрат, только у него стороны разные.


Эллипс — это круг, вписанный в квадрат размером три на два.
Re: Квадрат И ЕСТЬ прямоугольник
От: Poudy Россия  
Дата: 08.03.07 17:28
Оценка: 13 (1) -1
Кажется, пример про квадрат и прямоугольник совершенно идиотский, однако это не так.
В том или ином виде эта задача регулярно всплывает.
Например:
"файл" — "бинарный файл" — "текстовый файл",
"файл" — "файл только для чтения"
"контрол" — "контрол-контейнер" — "табконтрол"
"коллекция" — "список" — "типизированный список"
"маршалер" — "конкретный маршалер"

и уже упоминаемые здесь "матрица" — "квадратная матрица".


Мое решение такое:

    class Rectangle
    {
        public Rectangle(int width, int height)
        {
            this.width = width;
            this.height = height;
        }
        public Rectangle(int squareSide)
            : this(squareSide, squareSide)
        {
        }

        public bool IsSquare
        {
            get { return this.width == this.height; }
        }

        private int width;
        public int Width
        {
            get { return this.width; }
            set { this.width = value; }
        }

        private int height;
        public int Height
        {
            get { return this.height; }
            set { this.height = value; }
        }
    }


Оно нехорошо только тем, что нельзя задать определение функции, которая принимает квадрат.
Вообще это тоже серьезный недочет, однако мы как-то живем с функциями, которые принимают int, но он должен быть > 0, и с функциями, которые принимают файл, который должен быть доступен на запись. И понятно почему!

Открытое наследование, как наследование и интерфейса, и реализации, практически всегда используется на практике как средство уточнения типа. конкретизации. А реализация интерфейса — как обобщение. Щас я имею в виду C#. Т.е. если я вижу, что человек отнаследовался от Control, я понимаю — он хочет конкретизировать Control, заюзать функциональность базового класса. И я не должен ждать от него соблюдения LSP. Если же я вижу реализацию интерфейса IComponent, я понимаю — человек хочет встроить свой класс в инфраструктуру компонентов и жду от него соблюдения LSP. Потому как если он не соблюдет, уже готовый код инфраструктуры завалится с исключением и класс этот никуда не встроится. Вот почему на практике программист обычно понимает что к чему.

IMHO, объектные системы должны быть написаны именно так. Т.е. чтобы а) не плодить интерфейсы ISquare, которые все равно бесполезны при изменяемых объектах, б) не плодить ISquare, когда вариантов "фигур" очень много (например, они задаются пересечением 3х енумов по 10 записей в каждом) и в) позволять как-то узнать о том, можно ли вызывать ThisFunction(Rectangle), не обрамляя это в try/catch, нужны свойства по типу IsRectangle. Когда-то давно в таком же обсуждении я заморочился и написал большой пример
Автор: Poudy
Дата: 17.01.05
.
Re[2]: Квадрат И ЕСТЬ прямоугольник
От: Lazy Cjow Rhrr Россия lj://_lcr_
Дата: 09.03.07 08:23
Оценка:
Poudy,

P>IMHO, объектные системы должны быть написаны именно так. Т.е. чтобы а) не плодить интерфейсы ISquare, которые все равно бесполезны при изменяемых объектах, б) не плодить ISquare, когда вариантов "фигур" очень много (например, они задаются пересечением 3х енумов по 10 записей в каждом) и в) позволять как-то узнать о том, можно ли вызывать ThisFunction(Rectangle), не обрамляя это в try/catch, нужны свойства по типу IsRectangle. Когда-то давно в таком же обсуждении я заморочился и написал большой пример
Автор: Poudy
Дата: 17.01.05
.


Хм, за 2 года твои взгляды однако сильно не изменились
Автор: Poudy
Дата: 16.01.05
.
quicksort =: (($:@(<#[),(=#[),$:@(>#[)) ({~ ?@#)) ^: (1<#)
Re[2]: Бинарный файл -> текстовый файл
От: FDSC Россия consp11.github.io блог
Дата: 09.03.07 10:05
Оценка:
Здравствуйте, Poudy, Вы писали:

P>Кажется, пример про квадрат и прямоугольник совершенно идиотский, однако это не так.

P>В том или ином виде эта задача регулярно всплывает.
P>Например:
P> "файл" — "бинарный файл" — "текстовый файл",

Тут мне кажется, всё нормально. Где закавыка?

P> "файл" — "файл только для чтения"


Ну, это хороший пример
Re[3]: Квадрат И ЕСТЬ прямоугольник
От: Poudy Россия  
Дата: 10.03.07 07:26
Оценка:
Здравствуйте, Lazy Cjow Rhrr, Вы писали:

LCR>Poudy,


P>>IMHO, объектные системы должны быть написаны именно так. Т.е. чтобы а) не плодить интерфейсы ISquare, которые все равно бесполезны при изменяемых объектах, б) не плодить ISquare, когда вариантов "фигур" очень много (например, они задаются пересечением 3х енумов по 10 записей в каждом) и в) позволять как-то узнать о том, можно ли вызывать ThisFunction(Rectangle), не обрамляя это в try/catch, нужны свойства по типу IsRectangle. Когда-то давно в таком же обсуждении я заморочился и написал большой пример
Автор: Poudy
Дата: 17.01.05
.


LCR>Хм, за 2 года твои взгляды однако сильно не изменились
Автор: Poudy
Дата: 16.01.05
.


Ну я этот же пост и привел. Собственно, взглядам совсем не обязательно меняться за два года.
Кстати, если уж о взглядах ... за 2 года вот что поменялось:
1. LazyLoading — теперь сичтаю, что это вредная идея вообще;
2. Сущности — раньше думал, что должны быть "бесшовными" в плане общения с сервером, чтобы все было автоматом и незаметно. Сейчас думаю, что сервер и клиент должны всегда рассматриваться как совершенно разные приложения (ну примерно как сервер — ERP, а клиент — софт на КПК) и, соответственно, у сервера и клиента должны быть свои уникальные версии модели.
3. Про средства разработки в ERP — теперь считаю, все должно работать в VisualStudio.
Re[3]: Бинарный файл -> текстовый файл
От: Poudy Россия  
Дата: 10.03.07 07:32
Оценка:
Здравствуйте, FDSC, Вы писали:

FDS>Здравствуйте, Poudy, Вы писали:


P>>Кажется, пример про квадрат и прямоугольник совершенно идиотский, однако это не так.

P>>В том или ином виде эта задача регулярно всплывает.
P>>Например:
P>> "файл" — "бинарный файл" — "текстовый файл",

FDS>Тут мне кажется, всё нормально. Где закавыка?

Закавыка в дереве наследования. Как наследовать?
Вообще говоря, текстовый поток UTF-8 или UTF-16 "испортится", если из него взять и прочитать байт как из бинарного. По-другому должны работать откат на одну позицию и вообще seek. Какой-нибудь светлой голове может прийти в голову наследовать текстовый от бинарного (или наоборот . Я думаю в данном примере текстовый файл — это ваще отдельно. Т.е. не должно быть понятия "текстовый файл". Должно быть так: "бинарный файл" — "текстовый ридер".
Re[4]: И!
От: Poudy Россия  
Дата: 10.03.07 10:07
Оценка:
Здравствуйте, Poudy, Вы писали:

P>>>Должно быть так: "бинарный файл" — "текстовый ридер".


Непонятно написал. Забыл ометить, что "текстовый ридер" не наследуется от "бинарного файла", а агрегирует его.
Re: Топологически прямоугольникт- это изменённый квадрат
От: Michael7 Россия  
Дата: 25.04.07 06:32
Оценка: :)
Здравствуйте, igna, Вы писали:

I>Все-таки математика права, квадрат это прямоугольник,


Кстати, насчёт математики тоже не всё так просто, есть два подхода.
В обычной, хорошо нам знакомой, статической геометрии можно считать, что квадрат — это прямоугольник с равными сторонами.

Но есть ещё такой раздел математики как топология. Так вот с точки зрения топологии, наоборот, прямоугольник — это растянутый(или сжатый) квадрат. То есть, первичен именно квадрат.
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.