С++ позволяет определять в производном классе переменные и функции с теми же именами, что имеют переменные и функции в базовом классе. В этом случае переменные и функции производного класса будут скрывать одноименные переменные и функции базового класса.
Производный класс может определить функцию с тем же именем, что и функция в базовом классе, с тем же или другим списком параметров. Для компилятора такая функция будет существовать независимо от базового класса. И подобное определение функции в производном классе не будет переопределением функции из базового класса.
#include <iostream> class Person { public: Person(std::string name, unsigned age) : name(name), age(age) {} void print() const { std::cout << "Name: " << name << "\tAge: " << age << std::endl; } private: std::string name; unsigned age; }; class Employee: public Person { public: Employee(std::string name, unsigned age, std::string company): Person(name, age), company(company) { } void print() const { std::cout << "Works in " << company << std::endl; } private: std::string company; }; int main() { Employee tom{"Tom", 38, "Google"}; tom.print(); // Works in Google }
Здесь класс Person, который представляет человека, определяет функцию print()
, которая выводит значение переменных name и age.
Класс Employee, который представляет сотрудника компании и является производным от класса Person, также определяет функцию print()
, которая выводит значение переменной company.
В итоге объект Employee будет использовать реализацию функции print класса Employee, а не класса Person:
int main() { Employee tom{"Tom", 38, "Google"}; tom.print(); // Works in Google }
Функция print в Employee скрывает функцию print класса Person. Однако иногда может потребоваться возможность вызвать реализацию функции, которая определена именно в базовом классе. В этом случае можно использовать оператор :::
базовый_класс::функция
Например:
#include <iostream> class Person { public: Person(std::string name, unsigned age) : name(name), age(age) {} void print() const { std::cout << "Name: " << name << "\tAge: " << age << std::endl; } private: std::string name; unsigned age; }; class Employee: public Person { public: Employee(std::string name, unsigned age, std::string company): Person(name, age), company(company) { } void print() const { Person::print(); // вызываем функцию print из базового класса std::cout << "Works in " << company << std::endl; } private: std::string company; }; int main() { Employee tom{"Tom", 38, "Google"}; tom.print(); }
Здесь вызов
Person::print();
представляет обращение к функции print базового класса Person. В итоге мы получим другой консольный вывод:
Name: Tom Age: 38 Works in Google
Производный класс может иметь переменные с тем же именем, что и базовый класс, Хотя такие ситуации могут привести к путанице, и, возможно, представляют нелучший вариант наименования переменных. Тем не менее мы можем так делать. Например:
#include <iostream> class Integer { public: Integer(unsigned value): value(value) { } void printInteger() const { std::cout << value << std::endl; } protected: unsigned value; }; class Decimal: public Integer { public: Decimal(unsigned i_value, unsigned d_value): Integer(i_value), value(d_value) { } void printDecimal() const { std::cout << Integer::value << "." << value << std::endl; } protected: unsigned value; }; int main() { Decimal decimal{12345, 3456}; decimal.printInteger(); // 12345 decimal.printDecimal(); // 12345.3456 }
Здесь класс Integer представляет целое число, значение которого хранится в переменной value. Этот класс наследуется классом Decimal, который представляет дробное число. Целая часть хранится
в поле value класса Integer. А для хранения дробной части определена своя переменная value
. Причем переменная value в Integer имеет спецификатор protected
,
поэтому теоретически мы могли бы обращаться к ней в классе Decimal. Однако поскольку в Decimal определена своя переменная value, то она скрывает переменную value и базового класса.
Чтобы все таки обратиться к переменной value из базового класса, надо использовать оператор :::
базовый_класс::переменная
например:
Integer::value
Стоит учитывать, что таким образом мы можем обратиться только к переменным со спецификаторами public
и protected
. К приватным же переменным базового класса мы так обратиться не можем.