Объектно-ориентированное программирование, страница 11

cout <<s<<": ";

int n=0;

while (!(cin >> n) || n < min || max < n)

{

  Clear(cin);

  cout <<"\nOut of range: ("<<min<<", "<<max<<")\n"

    << "\nEnter "<<s<<": ";

}

Clear(cin);

return n;

}

//============= Class Man Declaration ==============//

class Man //----- Базовый класс

{

protected: // Данные, передаваемые по наследству

char *name;

int age;

public:    // Два конструктора

Man() { name=0; age=0; }

Man (const Man& m)

{

  name = strcpy (new char[strlen(m.name)+1], m.name);

  age = m.age;

}

~Man()      // Деструктор

{

  printf("\nDeleting: %s\n", name);

  delete [] name;

}

char* Class() { return "Man "; } // Методы, передаваемые по наследству

void In()

{

  printf("\n\nName: ");    gets(buf);

  name = strcpy(new char[strlen(buf) + 1], buf);

  age = ::In ("Age", 1,150);

}

void Out()

{

  printf ("\n%s %s\t Age: %d", Class(), name, age);

}

};

class Stud : public Man    //----- Производный класс

{

protected:       // Унаследовал поля имени и возраста

int course;     // Завел новое поле

public:

Stud() : Man() // Конструкторы сначала создают объект класса Man

{

  course=0;

}

Stud (const Stud& m) : Man(m)

{

  course = m.course;

}

char* Class()

{

  return strcat (strcpy (buf, Man::Class()), ": Stud");

}

void In()         // Переопределенные методы

{

  Man::In();       // Вызов родительской версии

  course = ::In ("Course", 0, 6);

}

void Out()

{

  printf("\n%s", Class());

  Man::Out();      // Вызов родительской версии

  printf("\tCourse: %d", course);

}

};

class Prof : public Man    //----- Еще один производный класс

{

protected:     // Унаследовал поля имени и возраста

int publ;     // Завел свои уникальные данные

char* dept;

public:      // Конструкторы сначала создают объект класса Man

Prof() : Man()

{

  publ=0;  dept=0;

}

Prof (const Prof& m) : Man(m)

{

  publ = m.publ;

  dept = strcpy(new char[strlen(m.dept)+1], m.dept);

}

~Prof()

{

  printf("\nDeleting: %s\n", dept);

  delete [] dept;

}

char* Class()

{

  return strcat (strcpy (buf, Man::Class()), ": Prof");

}

void In()

{

  Man::In();   // Вызов родительской версии

  publ = ::In("Publications", 1, 500);

  printf("Dept: ");

  gets(buf);

  dept = strcpy (new char[strlen(buf)+1], buf);

}

void Out()

{

  printf("\n%s", Class());

  Man::Out();    // Вызов родительской версии

  printf("\tPublications: %d  Dept: %s", publ, dept);

}

};

void main()

{

Man man;

man.In();   man.Out();   // Родительские версии методов

printf("\n\n\tClass of Man = %s", man.Class());

printf("\n\tSizeof(Man) = %d", sizeof(Man));

Stud stud;

stud.In();  stud.Out();  // Версии производного класса Stud

printf("\n\n\tClass of Stud = %s", stud.Class());

printf ("\n\tSizeof(Stud) = %d", sizeof(Stud));

Prof prof;

prof.In();  prof.Out(); // Версии производного класса Prof

printf("\n\n\tClass of Prof = %s", prof.Class());

printf ("\n\tSizeof(Prof)=%d", sizeof(Prof));

puts("\n\n");

}

При описании производного класса синтаксис с использованием двоеточия (class Stud : public Man) устанавливает иерархию между классом и подклассом. Таким образом, Man является родительским классом по отношению к классу Stud. Мнемоническое правило «создан класс Студент Мэнович» помогает запомнить, кто есть родитель. В классе Stud, несмотря на отсутствие явных указаний, присутствуют все данные и методы, унаследованные от класса Man, кроме конструктора. Вывод sizeof(Stud) доказывает это утверждение.

Объект класса

Размер объекта (байт)

Man

8 (2 поля по 4 байта)

Stud

12 (3 поля по 4 байта)

Prof

16 (4 полей по 4 байта)

Обратите внимание на описатель доступа или прав пользования наследуемыми данными и методами в заголовках производных классов. Наличие описателя public означает, что protected и public члены базового класса при наследовании попадают соответственно в protected и public секции производного класса. Здесь допустима следующая мнемоника: Студент публично заявил, что он сын Человека и наследует все данные и методы своего отца с теми же правами пользования. Если создать класс

class TechnoStud: public Stud;

производный от Студента, то он будет являться сыном Студента и внуком Человека и наследует все имущество и права пользования своих предков. Каждый объект класса TechnoStud, также как и Stud, будет иметь свои собственные копии данных name и age. В методе In класса Stud мы вызываем одноименный метод базового класса Man с целью ввода унаследованных данных. Отметьте, что двойное двоеточие в операторе Man::In(); (:: — scope operator) означает принадлежность метода классу Man, в отличие от одноименного метода класса Stud. Говорят, что метод Stud::In скрывает (hides) наследованный метод, однако операция ::, совместно с описателем Man позволяет получить доступ к родительской версии. Эта же мысль содержится в высказывании: метод In базового класса воспроизведен внутри метода Stud::In. Последний метод не только содержит в себе вызов одноименного метода базового класса, но и дополнен другими операторами. Таким образом, обработка унаследованных данных возложена на метод родительского класса, свое же поле данных (course) обрабатывается своим оператором.