Доступ к членам подкласса из указателя суперкласса C ++ - PullRequest
4 голосов
/ 01 апреля 2010

У меня есть массив пользовательских объектов Student. CourseStudent и ResearchStudent наследуются от Student, и все экземпляры Student являются одним или другим из них.

У меня есть функция для просмотра массива, определения подтипа каждого студента и вызова для него функций-членов, специфичных для подтипа.

Проблема в том, что эти функции не перегружены, они не найдены в Student, поэтому компилятор поднимает шум.

Если у меня есть указатель на студента, есть ли способ получить указатель на подтип этого студента? Должен ли я сделать что-то вроде фальшивого приведения здесь, чтобы обойти ошибку времени компиляции?

Ответы [ 5 ]

10 голосов
/ 01 апреля 2010

Лучше всего было бы использовать виртуальные функции:

class Student
{
   // ...
   virtual void SpecificFunction() = 0; /* = 0 means it's abstract; it must be implemented by a subclass */
   // ...
};

class CourseStudent
{
    void SpecificFunction() { ... }
};

Тогда вы можете сделать:

Student *student;
student->SpecificFunction();

(хуже) альтернатива может использовать dynamic_cast:

Student *student;
CourseStudent *cs = dynamic_cast<CourseStudent *>(student);

if (cs) {
   /* student is a CourseStudent.. */
   cs->SpecificFunction();
}
6 голосов
/ 01 апреля 2010

Вам нужен динамический бросок:

Student * s = new ...;    // create student of some sort

if ( ResearchStudent * r = dynamic_cast<ReasearchStudent*>( s ) ) {
   r->ResFunc();
}
else if ( CourseStudent * c = dynamic_cast<CourseStudent*>( s ) ) {
   c->CourseFiunc();
}
else {
   throw "unknown student type";
}

Обратите внимание, что при этом используется информация о типах, поддерживаемая компилятором, при условии, что в классе есть хотя бы одна виртуальная функция - если все остальное не сработает, сделайте деструктор виртуальным (как и должно быть в этом случае в любом случае). Вы всегда должны отдавать предпочтение такому подходу, чтобы поддерживать информацию своего типа.

3 голосов
/ 01 апреля 2010

Виртуальные функции здесь неуместны, потому что функции-члены подкласса являются специфическими для этих подклассов (например, CourseStudent имеет список модулей, тогда как ResearchStudent нет, поэтому реализация функции getUnits () в ResearchStudent вообще не будет иметь смысла )

Я немного читал о динамических и статических приведениях ( cplusplus.com typecasting ), и в этом случае я думаю, что статическое приведение более уместно.

Общим недостатком static_cast является то, что он не выполняет никакой проверки во время выполнения, чтобы убедиться, что объект, приведенный к подтипу, фактически является этим подтипом, а не каким-то другим. В этом случае я специально проверяю тип перед тем, как выполнить тип (используя закрытый член данных, который установлен в конструкторе подкласса и не имеет мутатора), поэтому, пока моя проверка хороша, не должно быть проблем со статическим приведением , Статическое приведение более эффективно, так как динамическое приведение требует больше ресурсов времени выполнения для проверки типов.

Там, где есть вероятность того, что элемент не является ожидаемым типом, статическое приведение не будет подходящим, поэтому я бы пошел на динамическое приведение (это назначение, поэтому после отправки кода не нужно будет поддерживать код так что нет риска, что кто-то испортит это позже).

2 голосов
/ 01 апреля 2010

Это почти наверняка случай использования чисто виртуальной функции-члена в базовом классе с последующим переопределением в производных классах, где вы выполняете реальную работу.

1 голос
/ 01 апреля 2010

Для этого вам нужно static_cast. Поскольку эти функции не являются виртуальными членами базового класса, их нельзя вызывать с помощью указателя на указатель на базовый класс. Вам необходимо явно привести к фактическому типу объекта.

Эту проблему обычно лучше всего решить с помощью виртуальных функций - вам больше не понадобится проверка типов объектов в вашем коде, будет меньше кода и меньше ошибок.

...