28. Предефиниране на функции елементи от базовия клас в производния клас.
производният клас може да предефинира функции елементи на базовия клас; ако в производния клас се опише функция елемент със същото име както функция елемент на базовия клас, то версията на тази функция в производния клас предефинира версията от базовия клас; за да се направи достъпна версията на функцията от базовия клас за производния клас, трябва да се използва бинарната операция за разрешаване на област на действие ‘::’;
Примерна програма:
#include
#include
#include
#include
class Employee {
public:
Employee (const char *, const char *);
void print () const;
~Employee ();
private:
char *firstName, *lastName;
} ;
Employee::Employee (const char *first, const char *last)
{ firstName = new char [ strlen (first) + 1];
assert (firstName != NULL);
strcpy (firstName, first);
lastName = new char [ strlen (last) + 1];
assert (lastName != NULL);
strcpy (lastName, last);
}
void Employee::print () const
{ cout << firstName << ‘ ‘ << lastName; }
Employee::~Employee ()
{ delete []firstName; delete []lastName; }
class HourlyWorker : public Employee
{ public:
HourlyWorker (const char *, const char *, float, float);
float getPay () const;
void print () const;
private:
float wage, hours;
} ;
HourlyWorker::HourlyWorker (const char *first, const char *last,
float initHours, float initWage) : Employee (first, last)
{ hours = initHours; wage = initWage; }
float HourlyWorker::getPay () const
{ return wage*hours; }
void HourlyWorker::print () const
{ Employee::print ();
cout << “ - $” << setiosflags (ios::fixed | ios::showpoint)
<< setprecision (2) << getPay () << endl;
}
void main ()
{ HourlyWorker h ( “Иван”, “Петров”, 40, 7.50);
h.print ();
}
функцията елемент print на класа HourlyWorker е пример за предефинирана функция елемент на базов клас в производен клас;
функции елементи от базовия клас често се предефинират в производния клас за изпълняване на някои по-специфични действия; тези предефинирани функции понякога извикват версията на функцията от базовия клас, за да изпълнят част от новата задача;
29. Използване на конструктори и деструктори в производни класове.
при създаване на обект от производен клас, конструкторът на производния клас винаги отначало извиква конструкторите на базовите класове, след това конструкторите на обектите елементи на производния клас и най-накрая се изпълнява самият конструктор на производния клас;
при унищожаване на обект от производен клас, деструкторите се извикват в ред, обратен на този в който са извикани съответните конструктори;
редът, в който се извикват конструкторите на обектите елементи, е редът, в който те са описани в дефиницията на класа; на този ред не влияе последователността, в която са изброени инициализаторите на обектите елементи в заглавието на конструктора;
редът, в който се извикват конструкторите на базовите класове, е редът, в който тези класове са посочени в заглавието на производния клас; на този ред не влияе последователността, в която са посочени конструкторите на базовите класове в описанието на конструктора на производния клас;
в конструктора на производния клас при явно извикване на конструкторите на базовия клас се използва списък от инициализатори на елементи; ако такъв списък не се опише, конструкторът на производния клас неявно ще извика конструкторите с аргументи по премълчаване на базовия клас; ако производният клас няма конструктор, то вграденият конструктор по премълчаване на производния клас ще извика конструкторите по премълчаване на базовия клас;
Примерна програма:
#include
class Point {
public:
Point (float = 0.0, float = 0.0);
~Point ();
protected:
float x, y;
} ;
Point::Point (float a, float b)
{ x = a; y = b;
cout << “Конструктор на Point: “ << ‘[‘ << x << “, “ << y << ‘]’ << endl;
}
Point::~Point ()
{ cout << “Деструктор на Point: “ << ‘[‘ << x << “, “ << y << ‘]’ << endl; }
class Circle : public Point
{ public:
Circle (float = 0.0, float = 0.0, float = 0.0);
~Circle ();
private:
float radius;
} ;
Circle::Circle (float r, float a, float b) : Point (a, b)
{ radius = r;
cout << “Конструктор на Circle: “ << radius << ‘[‘ << x << “, “ << y << ‘]’
<< endl;
}
Circle::~Circle ()
{ cout << “Деструктор на Circle: “ << radius << ‘[‘ << x << “, “ << y << ‘]’
<< endl;
}
void main ()
{
{ Point p (1.1, 2.2); }
Circle circle1 (4.5, 7.2, 2.9);
Circle circle2 (10, 5, 5);
}
резултат от изпълнението:
Конструктор на Point: [1.1, 2.2]
Деструктор на Point: [1.1, 2.2]
Конструктор на Point: [7.2, 2.9]
Конструктор на Circle: 4.5[7.2, 2.9]
Конструктор на Point: [5, 5]
Конструктор на Circle: 10[5, 5]
Деструктор на Circle: 10[5, 5]
Деструктор на Point: [5, 5]
Деструктор на Circle: 4.5[7.2, 2.9]
Деструктор на Point: [7.2, 2.9]
конструкторите и операцията за присвояване не се наследяват от производните класове; въпреки това, конструкторите и операцията за присвояване на производните класове могат да извикват конструкторите и операцията за присвояване на базовите класове;
30. Множествено наследяване.
при простото наследяване, всеки производен клас се поражда само от един базов клас; йерархията при простото наследяване може да се изобрази чрез дърво; при множественото наследяване, производният клас се поражда от два или повече базови класа; йерархията при множественото наследяване може да се изобрази чрез ориентиран ацикличен граф; йерархията на наследяването може да бъде с произволна дълбочина в границите на физическите ограничения за конкретната система;
Примерна програма:
#include
class Base1 {
public:
Base1 (int x) { value = x; }
int getData () const { return value; }
protected:
int value;
} ;
class Base2 {
public:
Base2 (char c) { letter = c; }
char getData() const { return letter;}
protected:
char letter;
} ;
class Derived: public Base1, public Base2
{ friend ostream& operator<< (ostream &, const Derived &);
public:
Derived (int, char, float);
float getReal () const;
private:
float real;
} ;
Derived::Derived ( int i, char c, float f) : Base1 (i), Base2 (c)
{ real = f; }
float Derived::getReal () const
{ return real; }
ostream &operator<< (ostream &output, const Derived &d)
{ output << “Цяло: “ << d.value << endl
<< “Символ: “ << d.letter << endl
<< “Реално: “ << d.real << endl;
return output;
}
void main ()
{ Base1 b1(10), *base1Ptr; Base2 b2 (‘z’), *base2Ptr;
Derived d (7, ‘A’, 3.5);
cout << b1.getData() << endl
<< b2.getData() << endl
<< d << endl;
cout << d.Base1::getData() << endl
<< d.Base2::getData() << endl
<< d.getReal() << endl;
base1Ptr = &d;
cout << base1Ptr -> getData() << endl;
base2Ptr = &d;
cout << base2Ptr -> getData() << endl;
}
в примера класът Derived се поражда от два класа Base1 и Base2 чрез множествено наследяване – то се указва с ‘:’ след името на класа и следващ списък на базовите класове, разделени със запетаи;
конструкторът на Derived извиква конструкторите на всеки от своите базови класове Base1 и Base2 с използване на списък от инициализатори на елементи; както знаем, конструкторите на базовите класове се извикват в този ред, в който те са описани в заглавието на производния клас Derived;
тъй като функцията operator<< е приятелска за производния клас Derived, тя има пряк достъп до защитените елементи value и letter от базовите класове Base1 и Base2;
по-нататък възниква проблем - един обект от клас Derived съдържа функции с еднакви имена; това са наследените функции getData от базовите класове Base1 и Base2; този проблем се решава лесно с помощта на бинарната операция за разрешаване на област на действие;
Сподели с приятели: |