Dziedziczenie klas
Z poprzedniego projektu (zobacz) importujemy do nowego projektu utworzoną wcześniej klasę o nazwie Figura.cs. Import wykonamy z opcji menu Projekt
Wynikiem jest pojawienie się importowanego pliku w oknie Eksploratora rozwiązań. Patrz poniższa ilustracja
UWAGA! Użycie kodu tak zaimportowanej klasy z innej przestrzeni nazw wymaga zaimportowania tej przestrzeni nazw. W omawianym przykładzie to instrukcja
using WlasciwosciFigur;
Patrz poniższy kod
Wskazówka:
using System.Windows.Forms;
using WlasciwosciFigur;
namespace DziedziczenieWlasciwosciFigur
{
public partial class Form1 : Form
{
private Figura fig;
public Form1()
{
InitializeComponent();
}
}
}
Tworzymy klasą która dziedziczy po innej klasie
W standardowy sposób tworzymy nową klasę przykładowo o nazwie Trojkat. W kodzie nowo utworzonej klasy importujemy klasę Figury (using WlasciwosciFigur). Klasie Trojkat przypisujemy dziedziczenie po klasie Figury. Patrz poniższy rysunek
Kompilator zgłosi błąd związany z potrzebą deklaracji konstruktora. Skorzystamy z proponowanego rozwiązania. Rozwiązanie wpisze za nas niezbędne kod konstruktora
Wskazówka:
namespace DziedziczenieWlasciwosciFigur
{
internal class Trojkat : Figura
{
public Trojkat(int ileOdcinkow) : base(ileOdcinkow)
{
}
}
}
Do klasy Figura dopiszemy funkcje liczącą obwód figury. Przejdź do pliku Figura.cs i wprowadź poniższy kod:
Wskazówka:
public float Obwod()
{
float obw = 0;
foreach (float o in odcinek) obw += o;
return obw;
}
Obiekt klasy dziedziczącej po innej klasie
W głównej klasie projektu Form1 (plik Form1.cs) zadeklarujemy obiekt klasy Trojkat i spróbujemy przypisać mu długości boków oraz obliczyć obwód. Funkcje liczącą obwód zakodujemy w klasie Fogura. Będzie to praktyczniejsze podejście, ponieważ każda figura ma obwód, który liczy się na jednakowych zasadach.
Do klasy Figura wprowadź poniższy kod funkcji. Nadaj jej atrybut public
Wskazówka:
public float Obwod()
{
float obw = 0;
foreach (float o in odcinek)
obw += o;
return obw;
}
Na głównej formatce przygotuj odpowiednie kontrolki. Poniżej propozycja układu
Zadeklaruj obiekt oparty na nowo utworzonej klasie Trojkat
Wskazówka:
public partial class Form1 : Form
{
private Trojkat trojkat;
public Form1()
{
InitializeComponent();
}
W kontrolce Button obsłuż zdarzenie Click przy pomocy, którego wprowadzi się dane związane z długością boków trójkąta
Wskazówka:
private void button1_Click(object sender, EventArgs e)
{
//usun stary trójkąt
if(trojkat!=null) { trojkat = null; }
//brak zabezpieczenia przed konwersją pustych txtBoxów
//lub błednie wypełnionych
trojkat = new Trojkat(3);
trojkat.UstawDlugosc(0,(float)Convert.ToDouble(textBox1.Text));
trojkat.UstawDlugosc(1,(float)Convert.ToDouble(textBox2.Text));
trojkat.UstawDlugosc(2,(float)Convert.ToDouble(textBox3.Text));
//czyść poprzednie wpisy
textBox4.Text= string.Empty;
textBox4.AppendText("Obwód:" + String.Format("{0,0:F2} cm", trojkat.Obwod()));
}
W powyższym kodzie widać wykorzystanie dziedziczenia po klasie Figura. Są to metody UstawDlugosc oraz Obwod. Skompiluj program i sprawdź efekt działania
Z podanych długości boków nie można zbudować trójkąta. W klasie Trojkat zakodujemy metodę sprawdzająca czy podane boki utworzą trójkąt
Wskazówka:
public bool CzyTrojkat()
{
if (Odcinek[0] + Odcinek[1] > Odcinek[2] &&
Odcinek[1] + Odcinek[2] > Odcinek[0] &&
Odcinek[2] + Odcinek[0] > Odcinek[1])
return true;
else
{
MessageBox.Show(
"Z podanych boków nie można zbudować trójkąta.",
"Komunikat",
MessageBoxButtons.OK,
MessageBoxIcon.Information
);
return false;
}
}
W kodzie głównej klasy Form1 zwrócimy komunikat, że podane dane nie tworzą trójkąta. Jeżeli tworzą, to wykonamy dalsze obliczenia.
Zmodyfikowany kod zdarzenia Click kontrolki Button
Wskazówka:
private void button1_Click(object sender, EventArgs e)
{
//usun stary trójkąt
if(trojkat!=null) { trojkat = null; }
//brak zabezpieczenia przed konwersją pustych txtBoxów
//lub błednie wypełnionych
trojkat = new Trojkat(3);
trojkat.UstawDlugosc(0,(float)Convert.ToDouble(textBox1.Text));
trojkat.UstawDlugosc(1,(float)Convert.ToDouble(textBox2.Text));
trojkat.UstawDlugosc(2,(float)Convert.ToDouble(textBox3.Text));
//czyść poprzednie wpisy
textBox4.Text= string.Empty;
if (!trojkat.CzyTrojkat()) return;
textBox4.AppendText("Obwód:"
+ String.Format("{0,0:F2} cm", trojkat.Obwod())
);
}
I efekt działania dla błędnych danych
Skoro mamy trójkąt, to możemy obliczyć jego pole. Skorzystamy ze wzoru Herona (zobacz)
Do klasy Trojkat dopisz poniższy kod
Wskazówka:
public float Pole()
{
float p = (Odcinek[0] + Odcinek[1] + Odcinek[2]) / 2;
return (float) Math.Sqrt(
p * (p - Odcinek[0])
* (p - Odcinek[1])
* (p - Odcinek[2]) );
}
W głównym pliku projektu (Form1.cs) oblicz pole trójkąta i zwróć wynik w kontrolce TextBox jako kolejny wiersz.
Wskazówka:
private void button1_Click(object sender, EventArgs e)
{
//usun stary trójkąt
if(trojkat!=null) { trojkat = null; }
//brak zabezpieczenia przed konwersją pustych txtBoxów
//lub błednie wypełnionych
trojkat = new Trojkat(3);
trojkat.UstawDlugosc(0,(float)Convert.ToDouble(textBox1.Text));
trojkat.UstawDlugosc(1,(float)Convert.ToDouble(textBox2.Text));
trojkat.UstawDlugosc(2,(float)Convert.ToDouble(textBox3.Text));
//czyść poprzednie wpisy
textBox4.Text= string.Empty;
if (!trojkat.CzyTrojkat()) return;
textBox4.AppendText("Obwód:"
+ String.Format("{0,0:F2} cm", trojkat.Obwod())
+ Environment.NewLine);
textBox4.AppendText("Pole:"
+ String.Format("{0,0:F2} cm^2", trojkat.Pole()));
}
Sprawdź efekt działania.
Nadpisywanie metod klasy bazowej
Nadpisywanie metod klasy bazowej w klasie pochodnej odbywa się słowem kluczowym override. Nadpisanie jest możliwe, wtedy gdy w wybranych metodach klasy bazowej użyjemy przy deklaracji metod słowa kluczowego virtual.
Dla przykładu w tym projekcie utworzymy klasę potomną Okrąg, która będzie oparta na klasie bazowej Figura. Obwód okręgu liczony jest inaczej niż pozostałych figur. Tu przyjmiemy, że podawany odcinek jest promieniem. Stąd nadpiszemy metodę public float Obwod() z klasy Figura.
Aby to zrobić, wspomnianą metodę definiujemy jako wirtualną
Wskazówka:
public virtual float Obwod()
{
float obw = 0;
foreach (float o in odcinek)
obw += o;
return obw;
}
Do projektu dodajemy klasę Okrąg, a w niej tworzymy nadpisywanie
Wskazówka:
using WlasciwosciFigur;
namespace DziedziczenieWlasciwosciFigur
{
internal class Okrag : Figura
{
public Okrag(int ileOdcinkow) : base(ileOdcinkow)
{
}
public override float Obwod()
{
//odcinek jest promieniem
//wiec obów okregu to 2piR
return (float)(2*Math.PI*Odcinek[0]);
}
}
}
Przygotowani dodatkowych kontrolek w formatce
Przejdź do okna głównego tworzonej aplikacji i dodaj kontrolki dla okręgu. Proponowany układ kontrolek poniżej
W kodzie klasy Form1 zadeklaruj obiekt okrag
Wskazówka:
public partial class Form1 : Form
{
private Trojkat trojkat;
private Okrag okrag;
public Form1()
{
InitializeComponent();
}
W zdarzeniu Click kontrolki Button wprowadź kod związany z tworzeniem okręgu o zadanym promieniu odczytanym z kontrolki TextBox
Wskazówka:
private void button2_Click(object sender, EventArgs e)
{
//usun stary okrag
if (okrag != null) { okrag = null; }
//brak zabezpieczenia przed konwersją pustych txtBoxów
//lub błednie wypełnionych
okrag = new Okrag(1);
okrag.UstawDlugosc(0, (float)Convert.ToDouble(textBox8.Text));
//czyść poprzednie wpisy
textBox5.Text = string.Empty;
textBox5.AppendText("Obwód:"
+ String.Format("{0,0:F2} cm", okrag.Obwod())
+ Environment.NewLine);
}
Skompiluj program i sprawdź efekt działania
Zadanie:
We własnym zakresie napisz w klasie Okrag funkcje liczące średnicę i pole okręgu.
Pełne kody omawianych klas
Plik Form1.cs
Wskazówka:
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
using WlasciwosciFigur;
namespace DziedziczenieWlasciwosciFigur
{
public partial class Form1 : Form
{
private Trojkat trojkat;
private Okrag okrag;
public Form1()
{
InitializeComponent();
}
private void button1_Click(object sender, EventArgs e)
{
//usun stary trójkąt
if(trojkat!=null) { trojkat = null; }
//brak zabezpieczenia przed konwersją pustych txtBoxów
//lub błednie wypełnionych
trojkat = new Trojkat(3);
trojkat.UstawDlugosc(0,(float)Convert.ToDouble(textBox1.Text));
trojkat.UstawDlugosc(1,(float)Convert.ToDouble(textBox2.Text));
trojkat.UstawDlugosc(2,(float)Convert.ToDouble(textBox3.Text));
//czyść poprzednie wpisy
textBox4.Text= string.Empty;
if (!trojkat.CzyTrojkat()) return;
textBox4.AppendText("Obwód:"
+ String.Format("{0,0:F2} cm", trojkat.Obwod())
+ Environment.NewLine);
textBox4.AppendText("Pole:"
+ String.Format("{0,0:F2} cm^2", trojkat.Pole()));
}
private void button2_Click(object sender, EventArgs e)
{
//usun stary okrag
if (okrag != null) { okrag = null; }
//brak zabezpieczenia przed konwersją pustych txtBoxów
//lub błednie wypełnionych
okrag = new Okrag(1);
okrag.UstawDlugosc(0, (float)Convert.ToDouble(textBox8.Text));
//czyść poprzednie wpisy
textBox5.Text = string.Empty;
textBox5.AppendText("Obwód:"
+ String.Format("{0,0:F2} cm", okrag.Obwod())
+ Environment.NewLine);
textBox5.AppendText("Średnica:"
+ String.Format("{0,0:F2} cm", okrag.Srednica())
+ Environment.NewLine);
textBox5.AppendText("Pole:"
+ String.Format("{0,0:F2} cm^2", okrag.Pole())
+ Environment.NewLine);
}
}
}
Plik Figura.cs
Wskazówka:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
namespace WlasciwosciFigur
{
internal class Figura
{
private int n;//ilość odcinków
//okrąg ma jeden i jest to promien,
//trojkat ma trzy i są to boki itd.
private List<float> odcinek;
//dostęp do właściwości
public int IleOdcinkow
{
set{n= value;//ustaw ile docinków ma figura
odcinek.Clear();//czyśc liste odcinków
//ustaw długosci odcinko na zero
for (int i = 0; i < n; i++) odcinek.Add(0);
}
get{ return n;}//zwróć ilość odcinków
}
public List<float> Odcinek
{
get { return odcinek;}
}
//konstruktor
public Figura(int ileOdcinkow)
{
odcinek = new List<float>();
IleOdcinkow= ileOdcinkow;
}
//destruktor
~Figura()
{
odcinek.Clear();
odcinek = null;
}
//metody
public void UstawDlugosc(int i,float dlugosc)
{
if (i < odcinek.Count)
odcinek[i] = dlugosc;
else MessageBox.Show(
"Figura nie ma takiej ilości odcinków",
"Komunikat",
MessageBoxButtons.OK,
MessageBoxIcon.Error
);
}
//ustaw losowe dlugosci boków
public void UstawLosoweDlugosciBokow()
{
Random los=new Random();
for (int i = 0; i < n; i++)
UstawDlugosc(i, (float)los.NextDouble()*100+1);
}
public virtual float Obwod()
{
float obw = 0;
foreach (float o in odcinek)
obw += o;
return obw;
}
}
}
Plik Trojkat.cs
Wskazówka:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
using WlasciwosciFigur;
namespace DziedziczenieWlasciwosciFigur
{
internal class Trojkat : Figura
{
public Trojkat(int ileOdcinkow) : base(ileOdcinkow)
{
}
public bool CzyTrojkat()
{
if (Odcinek[0] + Odcinek[1] > Odcinek[2] &&
Odcinek[1] + Odcinek[2] > Odcinek[0] &&
Odcinek[2] + Odcinek[0] > Odcinek[1])
return true;
else
{
MessageBox.Show(
"Z podanych boków nie można zbudować trójkąta.",
"Komunikat",
MessageBoxButtons.OK,
MessageBoxIcon.Information
);
return false;
}
}
public float Pole()
{
float p = (Odcinek[0] + Odcinek[1] + Odcinek[2]) / 2;
return (float) Math.Sqrt(
p * (p - Odcinek[0])
* (p - Odcinek[1])
* (p - Odcinek[2]) );
}
}
}
Plik Okrag
Wskazówka:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using WlasciwosciFigur;
namespace DziedziczenieWlasciwosciFigur
{
internal class Okrag : Figura
{
public Okrag(int ileOdcinkow) : base(ileOdcinkow)
{
}
public override float Obwod()
{
//odcinek jest promieniem
//więc obów okręgu to 2piR
return (float)(2*Math.PI*Odcinek[0]);
}
public float Srednica()
{
return 2 * Odcinek[0];
}
public float Pole()
{
return (float)(Math.PI * Odcinek[0]);
}
}
}