Как уже отмечалось, класс-наследник получает в наследство все поля базового класса (хотя, если они были приватные, доступа к ним он не имеет). В этом легко убедиться, выведя на экран размеры базового класса TCurrency и класса-наследника Roubles:
cout << sizeof(TCurrency) << endl; cout << sizeof(Roubles) << endl;
Так как мы не добавляли полей в производный класс, то на экран в обоих случаях будет выдано одно и то же число — размер поля Summa. В классе Point3D мы добавили поле z, поэтому размер класса увеличился по сравнению с классом Point2D на размер типа double.
Добавляемые поля в наследнике могут совпадать и по имени, и по типу с полями базового класса. Конечно, специально так делать не следует, но это не запрещено стандартом, поэтому нужно разобраться, как обращаться к полям с одинаковыми именами. Модифицируем наш пример из листинга 8.5, добавив в базовый и производный классы поля с одинаковыми типами и именами (листинг 8.6).
Листинг 8.6. Одинаковые поля в базовом и производном классах
class Base { protected: int x; public:
Base(int x):x(x) { cout << "Base" << endl; } ~Base() { cout << "-Base" << endl; }
};
class Derived: public Base { int x; public:
Derived(int x):x(x),Base(x+1) { cout << "Derived" << endl; } ~Derived() { cout << "-Derived" << endl; } int f() { return (Base::x+x); }
};
В базовом классе мы объявили поле в защищенной секции, чтобы класс-наследник мог непосредственно к нему обращаться. Естественно, в производном классе новое поле скрывает поле базового класса, поэтому для доступа к полю базового класса необходимо использовать квалификатор класса, что и показано в методе f ().
Класс-потомок наследует все поведение базового класса. Это означает, что нет необходимости заново определять операции в классе-наследнике, если их поведение не изменяется по сравнению с поведением в базовом классе. Снова обратимся к классу Roubles, наследнику класса TCurrency, и проверим работу операций, выполнив простую программу, представленную в листинге 8.7.
= 0.0 = 1.01 = 5.03
Листинг 8.7. Проверка работы операций в классе-наследнике int main()
{ Roubles d; cout << d << endl; // d
++d; d++; cout << d << endl; // d
d+=4.02; cout << d << endl; // d
return 0;
}
В примере мы не стали проверять все методы, определенные в базовом классе, — и так понятно, что все они правильно работают с объектами класса-наследника, хотя определены в базовом классе.
Естественно, в классе-наследнике допустимо определять новые методы, что можно видеть в листинге 8.4: в производном классе Point30 определен метод getz(). Во вновь определяемых методах разрешается вызывать любые доступные методы базового класса. Если в классе-наследнике имя метода совпадает с именем метода базового класса, то метод производного класса скрывает все методы базового класса с таким именем. При этом прототипы могут не совпадать.
Таким образом, чтобы в методе-наследнике вызвать одноименный метод родительского класса, нужно задавать его с квалификатором класса. Добавим в класс Point 2D метод PrintQ для вывода на экран координат точки:
void PrintO const
{ cout << x <<','<< у: }
В производном классе Poi nt3D определим метод с тем же именем. Чтобы вывести координаты х и у, вызовем одноименный метод базового класса:
void PrintO const
{ Base::Print(): cout <<','<< z; }
Обновить программисту свое рабочее место помогут красивые http://8themes.ru тут.
Аналогично можно выполнять метод базового класса для объекта-наследника, например:
Poinr3D Т:
Т.PrintO: // вызов "родного" трехмерного метода
Т.Base::PrintO: // вызов "родительского" двухмерного метода
|