2013-12-12 3 views
0

Я хочу вывести содержимое каждого объекта из приведенного ниже вектора.Iterator не может получить доступ к методам членов производного класса

vector<Employees*> midzer; 

«Решение» Я нашел, выполнив следующие действия:

for (vector<Employees*>::iterator i = midzer.begin(); i != midzer.end(); ++i) 
    { 
     cout << 
     (*i)->getFirstName() << " " << // Base class method. 
     (*i)->getLastName() << "\n" << // Base class method. 
     (*i)->getSalary() << "\n" << // Base class method. 
     (*i)->getNumMeetings() << "\n" << // Derived class method. 
     (*i)->getNumVacationDays() << endl; //Derived class method. 
    } 

Вопрос заключается в том, что я получаю сообщение об ошибке о том, что getNumMeetings и getNumVacationDays не являются членами сотрудников (базовый класс).

Может ли кто-нибудь уточнить, почему итератор не может «увидеть» производные методы и, если возможно, предоставить решение для этого?

Задача состоит в создании «базы данных» сотрудников, обладающих функциональностью для создания и удаления различных типов сотрудников «на лету», а также для вывода всей базы данных, хорошо отформатированной.

Дополнительная информация:

  • Я только позволил создать один вектор.
  • Я должен создать базовый класс и три производных класса (Менеджер, Инженер и Исследователь).

/Kenneth

+0

Так оно и есть. Итератор в базовый класс не знает ничего о производных типах. – juanchopanza

+0

Является ли «Сотрудники» базовым классом? Если да, не могли бы вы попытаться отличить итератор от производного класса? (Отказ от ответственности: я недавно работал с Java в тонну, и моя память о эффектах каста C++ в лучшем случае нечеткая) – Trojan

+0

хорошие ответы ниже, но плохой ответ заключается в использовании динамического броска, чтобы попытаться скрыть указатель , затем распечатайте дополнительные функции, начиная с более конкретных типов указателей, и на тех итерациях, когда это будет успешно. – RichardPlunkett

ответ

0

Можно ли разработать, почему итератор не может «видеть» производные методы

компиляции ничего не известно о вызовах виртуальных функций, так что эти функции должны существовать в Employees (лучше название Employee, конечно?).

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

+0

Последние два метода относятся к одному из производных классов (еще не создали других). Если дизайн нарушен, у вас есть идея, как «исправить» дизайн? – Kenneth

+0

@ Kenneth: Да - создайте функцию «print» или что-то, что существует в вашей базе и всех ваших производных типах, и для каждого из них _implementation_ различаются по мере необходимости. –

+0

Будет ли это также работать, когда выведенные объекты находятся в случайном порядке .. как исследователь, инженер, менеджер, инженер (...). Я имею в виду функцию виртуальной печати, реализованную по-разному в каждом производном классе. который print() я вызываю с помощью итератора? Я достаточно хорошо объясняю свою озабоченность? – Kenneth

0

Использование полиморфизма?

Определить виртуальный член Функция печати, взяв ostream. Назови это. Попросите версию производного класса вызвать версию базового класса, а затем распечатайте дополнительную информацию.

+0

Когда вы говорите «взятие ostream», можете ли вы предоставить пример кода? – Kenneth

2

Вы не можете см. членов базового класса, потому что они не там. Вы должны бросить к производному типу к использованию их члены:

dynamic_cast<Manager*>(*i)->getNumMeetings() << "\n" << 

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

+0

Я вхожу в путь OO, хотя и довольно новый. Я предполагаю, что метод виртуального чтения будет чем-то вроде return (input data member), но у меня будет три производных класса, и при выводе информации из всех объектов (созданных из разных производных классов) итератор выяснит, что назвать где? Я думаю, что нет :) – Kenneth

+0

Конечно, если сбой dynamic_cast вы вызываете метод из нулевого указателя, который является неопределенным поведением. Вы также можете вызвать неопределенное поведение с static_cast, если вы собираетесь это сделать. – CashCow

+0

@ Kenneth, что вы действительно хотите, это просто 'cout << * i << endl' и функция' operator <<() 'для каждого из производных типов. –

0

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

Если вы знаете, что типы являются Менеджерами, то у вас действительно есть вектор указателей на менеджера.

Возможно, вам нужна абстрактная функция печати.

class Employee 
{ 
public: 
    virtual ~Employee(); 

    virtual std::ostream& print(std::ostream &) const = 0; 
}; 


class Manager : public Employee 
{ 
public: 
     virtual std::ostream& print(std::ostream &) const; 
}; 

std::ostream& Manager::print(std::ostream & os) const 
{ 
     // print, knowing I am a Manager 
    return os; 
} 


for (vector<Employees*>::iterator i = midzer.begin(); i != midzer.end(); ++i) 
{ 
    (*i)->print(std::cout); 
} 

Если вы на самом деле всегда, в одном векторе, всегда один и тот же тип, вы могли бы рассмотреть вопрос об изменении модели, чтобы отразить эти агрегаты. Вектор менеджеров - это не тип вектора сотрудников, ни наоборот.

+0

У меня есть оба менеджера, инженеры и исследователи в одном и том же векторе. И все они должны выводиться, когда итератор проходит цикл. – Kenneth

+0

Я выполнил ваш код выше. Моя программа компилируется, но после создания диспетчера ничего не выводится в окно консоли. Программа просто выходит нормально (код выхода 0).У вас есть идеи, почему это так? – Kenneth

0

Это работает только в обратном направлении. Таким образом, производный тип может «видеть» элементы своего базового типа (потому что он равен базовому типу), но базовый тип не может видеть члены производного типа (потому что это не производный тип).

Решение должно заключаться в реализации такой функции, как «печать» или «отображение» в базовом классе Employee, а затем переопределить ее в каждом из производных классов.

0

Проблема заключается не в итераторе, а в том, как вы структурировали свои классы.

Непонятно, как вы определили класс Employee и подклассы. В объектно-ориентированном дизайне базовый класс содержит интерфейсы, а подкласс или конкретные классы могут переопределять/реализовывать конкретные поведения. Это называется принципом program to interface. Для этого используйте виртуальные функции.

+0

Я расскажу о вашей ссылке. Спасибо друг. Базовый класс содержит три общих метода, которые используют все производные классы. Производные классы имеют несколько методов, специфичных для их «потребностей». – Kenneth

+0

Надеюсь, они содержат ключевые слова 'virtual'. Итератор - всего лишь обертка. Безопасно. – sarat

Смежные вопросы