Dziedziczenie właściwości.

0

Mam pytanie, mam bazową klasę Rectangle i chcę z niej dziedziczyć klasę Squere. Chciałem, żeby klasa Squere miała jedną właściwość np. Side, zamiast dwóch, ale wtedy bym musiał jakoś przysłonić właściwości z klasy bazowej i nie do końca wiem jak to zrobić. Rozwiązałem to w poniższy sposób, ale wydaje mi się to średnim rozwiązaniem. W C++ bym próbował coś z = delete, ale nie mogłem znaleźć czegoś analogicznego w C#. W jaki sposób najładniej to rozwiązać?


class Rectangle
    {
        public virtual double Height { get; set; }
        public virtual double Width { get; set; }
        
        public Rectangle(double height, double width)
        {
            Height = height;
            Width = width;
        }
  }

sealed class Squere : Rectangle
    {
        public override double Height { get { return base.Height; } set { base.Height = value; base.Width = value; } }
        public override double Width { get { return base.Width; } set { base.Height = value; base.Width = value; } }

        public Squere(double side) : base(side, side) { }
    }
3

Tak się nie robi, tak dziedziczenie nie działa.

Poczytaj o zasadzie podstawienia Liskov (np. https://www.tomdalling.com/blog/software-design/solid-class-design-the-liskov-substitution-principle/).

0

Te dwie linijki tekstu są nie potrzebne . Wystarczy tak :

    class Program
    {
        static void Main(string[] args)
        {
            Squere sq = new Squere(10);
            Console.WriteLine(sq.Height);
            Console.WriteLine(sq.Width);
        }
    }


    class Rectangle
    {
        public  double Height { get; set; }
        public double Width { get; set; }

        public Rectangle(double height, double width)
        {
            Height = height;
            Width = width;
        }
    }

    sealed class Squere : Rectangle
    { 
        public Squere(double side) : base(side, side) { }
    }
}

Klasa kwadrat nie powinna dziedziczyć po klasie prostokąt. Zły projekt .

1

@Zimny Krawiec: no tak średnio bym powiedział

Squere sq = new Squere(10);
sq.Width = 25;
sq.Height = 100;
 
Console.WriteLine(sq.Width);
Console.WriteLine(sq.Height);
0

Klasa kwadrat nie powinna dziedziczyć po klasie prostokąt. Zły projekt .

np

class Rectangle()
{
    public Rectangle(double side)
    {
         Height = Width = side;
    }
}

Obawiam się, że może. Tworzysz przeciążony konstruktor, który pobiera jeden argument. Nie ma znaczenia czy przypiszesz do wysokości lub szerokości bo są takie same.Właściwie powinieneś przypisać do obu.

0

Nie wiem, czy autor wciąż jest zainteresowany wątkiem, ale dziedziczenie prostokąt - kwadrat moim zdaniem powinno wyglądać tak:

class Rectangle
    {
        double _width;
        double _heigh;

        public Rectangle(double height, double width)
        {
            _width = width;
            _heigh = height;
        }


        public double AreaSize(double height, double width)
        {
            return height * width;
        }
        public double PerimeterLenght(double height, double width)
        {
            return 2 * (height + width);
        }
        

        public double Widht
        {
            get
            { return _width; }
            set
            {
                if (_width >= 0)
                {
                    _width = value;
                }
            }
        }
        public double Height 
        {
            get
            { return _heigh; }
            set
            {
                if (_heigh >= 0)
                {
                    _heigh = value;
                }
            }
        }

    }

class Square : Rectangle
    {
        public Square(double height, double width) : base(height, width)
        {
            _width = height;
            _heigh = height;
        }
        readonly double _width;
        readonly double _heigh;
    }

0

kwadrat moim zdaniem powinno wyglądać tak:

Oj chyba nie.

public double AreaSize(double height, double width)
public double PerimeterLenght(double height, double width)

Dlaczego nie korzystasz z pól prywatnych, które zostały zainicjalizowane przez konstruktor?
Po co przekazujesz przez argumenty dane, które wsadzasz tak naprawdę konstruktorem klasy?
Poza tym to także powinny być raczej własności, no bo po co z tego robić metody?

0

Dotykasz odwiecznego sporu, metoda czy własność. :)
A tak naprawdę, bo one są wykorzystywane w specyficzny sposób w klasie GetData().

https://github.com/igorzeler/Training/tree/master/4P-rectangle/4P-rectangle

0

No ale przecież takie rzeczy można włożyć do abstrakta jako metody/własności wirtualne.

A tak naprawdę, bo one są wykorzystywane w specyficzny sposób w klasie GetData().

W jakiej klasie GetData()? To jest przecież bez sensu, bo powielasz dane, do których masz dostęp od początku istnienia obiektu.

EDIT: patrzyłem na tego Gita i przecież te metody nie są w ogóle w tej klasie wykorzystywane. Miast tego korzystasz z konstruktora więc... podejrzewam, że nie bardzo wiesz co robisz. ;)

    class GetData
    {
        public Rectangle RectangleGetData()
        {
            Console.WriteLine("Podaj wysokość");
            double height = double.Parse(Console.ReadLine());
            Console.WriteLine("Podaj szerokosć");
            double widht = double.Parse(Console.ReadLine());
            var rec = new Rectangle(height, widht);
            return rec;
        }

        public Square SquareGetData()
        {
            Console.WriteLine("Podaj długość boku");
            double height = double.Parse(Console.ReadLine());
            double width = height;
            var squ = new Square(height, width);
            return squ;
        }
    }
1

Zrobię w nowym poście, bo w sumie chodzi już o konkretne rozwiązanie:

Nie lepiej tak?

    abstract class Square // rzecz jasna chodzi o nazwę Shape ;)
    {
        public double Width { get; }
        public double Height { get; }

        public virtual double AreaSize { get; }
        public virtual double PerimeterLenght { get; }

        public Square(double width, double height)
        {
            Width = width;
            Height = height;
        }
    }

    class Rectangle : Square
    {
        public override double AreaSize => Height * Width;
        public override double PerimeterLenght => 2.0 * (Height + Width);

        public Rectangle(double width, double height)
            : base(width, height)
        {

        }
    }

    class Program
    {
        static void Main(string[] args)
        {
            Square rect = new Rectangle(4.0, 2.5);
            Console.WriteLine($"AreaSize: {rect.AreaSize}, PerimeterLenght: {rect.PerimeterLenght}");
        }
    }

EDIT: pomyliłem Square z Shape ale to i tak nie oznacza, że rozwiązanie podane przez OP jest prawidłowe ;)

0

Zrób abstrakcyjną klasę figura albo wielokąt

0

Dam ci lepszy pomysł na naukę ze strony microsoftu

Tutaj jest mądry przykład:
https://docs.microsoft.com/pl-pl/dotnet/csharp/programming-guide/classes-and-structs/inheritance

0

A jeszcze lepiej zrobić ze Square interfejs.

0

Ja bym sobie już dał spokój z tymi figurami geometrycznymi

0

Masz, rację, była błąd zapisu tych samych właściwości w dwóch klasach i to mi powodowało błąd, w ten sposób co zrobiłem udało mi się go obejść. Rozumiem , że chodzi Tobie o to:


class Rectangle
    {
        public Rectangle(double height, double width)
        {
            Width = width;
            Height = height;
        }
        public double AreaSize(double height, double width)
        {
            return height * width;
        }
        public double PerimeterLenght(double height, double width)
        {
            return 2 * (height + width);
        }
        public double Width { get;  private set; }
        public double Height { get; private set; }
    }
0

Problem nie jest w tym jak to przełożyć mądrze na c# tylko z samym modelem klas . Bardziej zadanie dla matematyka niż programisty

1

Pisałem prywatnie i na forum że klasa Kwadrat nie jest w ogóle potrzebna . Jedna klasa Prostokąt wystarczy do obliczania obwodu i pola

0

Rozumiem, że kwadrat jest prostokątem ale tutaj w ogóle nie potrzebujesz dziedziczenia. ;) Kwadrat i prostokąt to specjalizacje, a nie abstrakty. Jeśli chcesz już koniecznie po czymś dziedziczyć to niech to będzie interfejs IShape.

Tak naprawdę Kwadrat i Prostokat powinny być sealed.

0

Klasę Prostokąt możemy wykorzystać do obliczania pola kwadratu i obwodu w innej klasie . Dziedziczenie nie jest potrzebne tak jak piszesz

0

Myślałem o czymś takim:

    interface IShape
    {
        double Field { get; }
    }

    sealed class Rectangle : IShape
    {
        private readonly double width;
        private readonly double height;

        public double Field => width * height;

        public Rectangle(double width, double height)
        {
            this.width = width;
            this.height = height;
        }
    }

    sealed class Square : IShape
    {
        private readonly double side;

        public double Field => side * side;

        public Square(double side)
        {
            this.side = side;
        }
    }

Po prostu kwadrat i prostokąt to końcowe specjalizacje.

1

Grzesiek, ja to wiem. Popatrz na post pierwszy w temacie.

Hehe, a dobra. To powinno być proste do osiągnięcia np. w ten sposób:

    class Rectangle
    {
        public virtual double Width { get; }
        public virtual double Height { get; }
    }

    class Square : Rectangle
    {
        public virtual double Side { get; }
        public override double Height => Side;
        public override double Width => Side;
    }
0

@grzesiek51114: jeśli zakładasz, że długości boków są tylko do odczytu, to Twoje rozwiązanie ma sens i jest zgodne z interpretacją figur w matematyce.

Ja mam takie rozwiązanie, że kwadrat wykorzystuje podobieństwo do prostokąta, ale nim nie jest. Mógłby istnieć interfejs I3DFigure, który rozszerza interfejs I2DFigure o właściwość Volume. Wtedy prostopadłościan (Cuboid) mógłby zawierać prywatną właściwość typu Rectangle jako podstawa i definiować dodatkową właściwość Depth lub trzy właściwości typu Rectangle - po jednej dla trzech różnych ścian, a sześcian (Cube) mógłby zawierać prywatną właściwość typu Cuboid.

public interface I2DFigure
{
    double Area { get; }
    double Perimeter { get; }
}

public class Rectangle : I2DFigure
{
    public double Width { get; set; }
    public double Height { get; set; }
    public double Area => Width * Height;
    public double Perimeter => 2 * Width + 2 * Height;

    public Rectangle(double width, double height)
    {
        Width = width;
        Height = height;
    }
}

public class Square : I2DFigure
{
    public double Width
    {
        get
        {
            return Rectangle.Width;
        }
        set
        {
            Rectangle = new Rectangle(value, value);
        }
    }
    public double Area => Rectangle.Area;
    public double Perimeter => Rectangle.Perimeter;

    public Square(double width)
    {
        Rectangle = new Rectangle(width, width);
    }

    private Rectangle Rectangle;
}
0

Dla tych co nie znają tych nowych konstrukcji

namespace ConsoleApp
{
    interface IInterfeis
    {
        int Wlasciwosc1 { get; set; }
        int Wlasciwosc2 { get; }
    }

        class Program
    {
        static void Main(string[] args)
        {
        }
    }

    class A : IInterfeis
    {
        int pole;
        public int Wlasciwosc1 { get => pole * pole; set => pole = value; }

        //public int Wlasciwosc2 => pole * pole; // skrócony zapis

        public int  Wlasciwosc2 { get => pole * pole; }

        public int Metoda1() => pole * pole; 
    }
}

6

Robienie specjalnej klasy kwadratu wyprowadzonej z prostokąta to bezsens. Czy ktokolwiek robi klasę wyprowadzoną z Person, dla osób, które mają nazwisko identyczne z imieniem? Albo komponent, którego kolor wnętrza jest identyczny z kolorem obrysu itd. Kwadrat to szczególny prostokąt, wystarczy dodać np. metodę statyczną do tworzenia tego szczególnego prostokąta np. makeSquare(int size) plus metodę testującą czy nasz prostokąt spełnia ten szczególny przypadek równości obu boków.
Druga kwestia to możliwość istnienia dwóch identycznych obiektów, które są różnych typów. Robimy obiekt klasy Rectangle o bokach 2 i 2 i obiekt Square też o boku 2, jak teraz wybrać z kolekcji figur wszystkie kwadraty? Na podstawie klasy nie da się, więc po co nam ta klasa? W konsekwencji, trzeba zablokować tworzenia obiektów klasy Rectangle, których width i height są takie same. Więc odpada już tworzenie konstruktorem, zostają metody np. statyczne klasy Rectangle , które będą zwracać raz Rectangle a raz Square. A jeśli obiekt Rectangle jest mutowalny i zmieni swój height na wartość równą z width to co wtedy? Więc znowu nasze klasy powinny zwracać wyłącznie obiekty niemutowalne.
A jeśli już koniecznie trzeba rozróżniać obiekty na podstawie klas, to należy odwrócić sytuację i zrobić klasę Square i wyprowadzić z niej Rectangle, choć wydaje się to wbrew logice. Wtedy następuje rozszerzenie klasy o nowe pole, nowe metody, choć problemy nadal pozostają.

0

Dlaczego Squere dziedziczy po Rectangle?
Lepiej byłoby zrobić klasę abstrakcyjną np: Shape która to ma pewną część wspólną..
Według mnie dziedziczenie Squere po Rectangle to jak dziedziczenie Ferrari po Maluchu.. :-(
Dobrze że ktoś przywołał Liskov - https://www.infragistics.com/community/blogs/b/dhananjay_kumar/posts/simplifying-the-liskov-substitution-principle-of-solid-in-c warto uczyć się pisać kod w ten sposób.

1 użytkowników online, w tym zalogowanych: 0, gości: 1