Поиск:

Ответ в темуСоздание новой темы Создание опроса
> Запутался с наследованием и полиморфизмом 
:(
    Опции темы
Нитонисе
Дата 2.11.2010, 19:20 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 917
Регистрация: 5.11.2009

Репутация: 2
Всего: 2



Есть класс А, у которого имеются потомки класс В и класс C.
Есть также класс D, одна из операций которого выглядит так
Код

void method(B*);
void method(C*);

то есть класс D должен работать с наследниками класса A.
Теперь пишу такой код
Код

A *a = new B;
D d;
d.method(a);

Компилятор ругается на последнюю строчку

Код

[C++ Error] Main.cpp(68): E2285 Could not find a match for 'D::method(A*)'


как мне научить класс D работать с разными потомками класса А?

Это сообщение отредактировал(а) Нитонисе - 2.11.2010, 19:20
PM MAIL   Вверх
baldina
Дата 2.11.2010, 19:26 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Завсегдатай
Сообщений: 3433
Регистрация: 5.12.2007
Где: Москва

Репутация: 1
Всего: 101



дело в том, что B и C являются А, но А не является ни B, ни C (Ту134 - самолет, но самолет - не обязательно Ту134)
в чем полиморфизм? в том, что принимая аргументом A* и вызывая виртуальную функцию, будут работать методы B или C, в зависимости от типа.
Цитата

как мне научить класс D работать с разными потомками класса А?

так:
Код

class A {
public:
  virtual void method (void);
};

class B: public A {
public:
  void method (void); // переопределение
};

class C: public A {
public:
  void method (void); // переопределение
};

class D {
 public:
  void method (A*a) { a->method (); // вызывается B::method или C::method
};

A *b = new B;
A *c = new C;
D d;
d.method(b); // вызывается B::method
d.method(c); // вызывается C::method


PM MAIL   Вверх
Нитонисе
Дата 2.11.2010, 19:41 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 917
Регистрация: 5.11.2009

Репутация: 2
Всего: 2



baldina,  так получается что работает метод, реализованный в классах В и С. Это не совсем то, что мне нужно. Мне нужно чтобы работал метод, реализованный в D.

Добавлено @ 19:45
То есть изначально метод класса D не знает какой именно потомок класса А будет его аргументом. Действует позднее связывание, тип аргумента определяется по факту переданного в метод указателя.

Это сообщение отредактировал(а) Нитонисе - 2.11.2010, 19:46
PM MAIL   Вверх
Artemon
Дата 2.11.2010, 20:09 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


а ты мне нравишься
***


Профиль
Группа: Завсегдатай
Сообщений: 1771
Регистрация: 24.2.2004
Где: Челябинск

Репутация: 7
Всего: 20



Цитата

Мне нужно чтобы работал метод, реализованный в D


Класс D вообще никак не участвует в наследовании, поэтому требование просто не корректное.

Цитата

То есть изначально метод класса D не знает какой именно потомок класса А будет его аргументом. Действует позднее связывание, тип аргумента определяется по факту переданного в метод указателя.


Пример который тебе показали, на 100% соответствует этому


--------------------
Контроль топлива на топливозаправщиках, мониторинг автотранспорта, расчет зарплаты водителей www.rscat.ru
PM MAIL   Вверх
Нитонисе
Дата 2.11.2010, 20:16 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 917
Регистрация: 5.11.2009

Репутация: 2
Всего: 2



Цитата(Artemon @  2.11.2010,  20:09 Найти цитируемый пост)
Пример который тебе показали, на 100% соответствует этому

Пример-то верный, только он немного не в тему. Мне надо чтобы метод D::method(A*) работал с собственными данными класса D, а по типу своего аргумента определял как именно с ними нужно работать. 
Я так понял у меня изначально постановка задачи неверная. Нужно сделать по примеру, который расписал baldina, а в реализации метода D::method(A*) выполнять проверку типа аргумента. Если указатель на B - то один набор операций, если это указатель на С - второй набор операций.
PM MAIL   Вверх
Artemon
Дата 2.11.2010, 20:57 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


а ты мне нравишься
***


Профиль
Группа: Завсегдатай
Сообщений: 1771
Регистрация: 24.2.2004
Где: Челябинск

Репутация: 7
Всего: 20



Не очень хорошая идея делать проверки. Зачем вам тогда полиморфизм ?
Вам нужно чтобы все производные классы (в вашем случае A и B) умели возвращать данные через одинаковые методы, тогда вы сможете сделать следующее (немного переделал пример для понятности):

Код

class InterfaceA {
public:
  virtual int GetData (void) = 0;
};

class B: public InterfaceA {
public:
  int GetData (void) {return 1;}
};

class C: public InterfaceA {
public:
  int GetData (void) {return 2;}
};

class D {
 public:
  void method (A*a) 
       { 
       DoAction(a->GetData());
       }

  protected:
         void DoAction(int a)
             {
              int c = 10 + a;
             }
};

A *b = new B;
A *c = new C;
D d;
d.method(b); // вызывается B::method
d.method(c); // вызывается C::method



Это сообщение отредактировал(а) Artemon - 2.11.2010, 20:58


--------------------
Контроль топлива на топливозаправщиках, мониторинг автотранспорта, расчет зарплаты водителей www.rscat.ru
PM MAIL   Вверх
Нитонисе
Дата 2.11.2010, 21:17 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 917
Регистрация: 5.11.2009

Репутация: 2
Всего: 2



Цитата(Artemon @  2.11.2010,  20:57 Найти цитируемый пост)
Не очень хорошая идея делать проверки. Зачем вам тогда полиморфизм ?Вам нужно чтобы все производные классы (в вашем случае A и B) умели возвращать данные через одинаковые методы, тогда вы сможете сделать следующее (немного переделал пример для понятности)

Не, тут дело в том, что проблемы вызвать нужную функцию из семейства А,В,С нет. Есть проблема правильно выполнить метод D::(A*). То есть в зависимости от того, какой фактический указатель передается в метод, я выполняю разные операции.
Код

class A 
{
};

class B: public A 
{
};

class C: public A 
{
};

class D 
{
 public:
  void method (A*a) 
       { 
            if (B *a = dynamic_cast<B*>(a))
                data += 1;
            if (C *c = dynamic_cast<C*>(a))
                data += 2;
       }

  protected:
    int data;     
};

A *b = new B;
A *c = new C;
D d;
d.method(b); // прибавляется 1
d.method(c); // прибавляется 2

PM MAIL   Вверх
Artemon
Дата 3.11.2010, 08:37 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


а ты мне нравишься
***


Профиль
Группа: Завсегдатай
Сообщений: 1771
Регистрация: 24.2.2004
Где: Челябинск

Репутация: 7
Всего: 20



Зачем тогда вообще нужны классы A и B

Передавайте в метод класса D элемент из перечисления

enum EActions
{
 eAction1 = 0,
 eAction2,
 eAction3
};

void method (EActions a) 
       { 
            switch(a)
                     {
                      case eAction1:
                                            data += 1; 
                                            break;
                     case eAction2:
                                           data += 2;
                                           break;
                     }
       }


--------------------
Контроль топлива на топливозаправщиках, мониторинг автотранспорта, расчет зарплаты водителей www.rscat.ru
PM MAIL   Вверх
Нитонисе
Дата 3.11.2010, 09:47 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 917
Регистрация: 5.11.2009

Репутация: 2
Всего: 2



Цитата(Artemon @  3.11.2010,  08:37 Найти цитируемый пост)
Зачем тогда вообще нужны классы A и B

Я пример упростил, но в реальной программе из потомков класса А берутся некоторые данные при выполнении D::method(A*).
PM MAIL   Вверх
Artemon
Дата 3.11.2010, 10:28 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


а ты мне нравишься
***


Профиль
Группа: Завсегдатай
Сообщений: 1771
Регистрация: 24.2.2004
Где: Челябинск

Репутация: 7
Всего: 20



Цитата

Я пример упростил, но в реальной программе из потомков класса А берутся некоторые данные при выполнении D::method(A*).


Все уже сказано выше, лично мне добавить нечего.


--------------------
Контроль топлива на топливозаправщиках, мониторинг автотранспорта, расчет зарплаты водителей www.rscat.ru
PM MAIL   Вверх
mes
Дата 3.11.2010, 10:31 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


любитель
****


Профиль
Группа: Участник Клуба
Сообщений: 7954
Регистрация: 14.1.2006

Репутация: 6
Всего: 250



Цитата(Artemon @  3.11.2010,  09:28 Найти цитируемый пост)
Все уже сказано выше, лично мне добавить нечего. 

не все smile  (хотя пример с GetData очень близок по сути к отсутствующему)

http://liveworkspace.org/code/ca23ab383de6...54a82098539f3d6

Это сообщение отредактировал(а) mes - 3.11.2010, 10:51


--------------------
PM MAIL WWW   Вверх
baldina
Дата 3.11.2010, 11:05 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Завсегдатай
Сообщений: 3433
Регистрация: 5.12.2007
Где: Москва

Репутация: 1
Всего: 101



mes, пример хороший и правильный. к сожалению, он вряд ли поможет ТС, а может и навредит, потому что 
Код

class D {
void method(B*);
void method(C*);
};
 
где B и C имеют общего предка, скорее всего следствие ошибок проектирования.
те редкие случаи, когда это действительно нужно, возникают на более высоком уровне абстракции, когда про полиморфизм в С++ ясно все и понятны его недостатки.
если я неправ, хотелось бы не технический, а жизненный пример smile
 smile из жизни самолетов  smile 
PM MAIL   Вверх
xvr
Дата 3.11.2010, 11:55 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Комодератор
Сообщений: 7046
Регистрация: 28.8.2007
Где: Дублин, Ирландия

Репутация: 48
Всего: 223



Перенесите разные части того, что нужно исполнять в классе D в классы B и C (в виде виртуальной функции, описанной в классе A), и вызывайте ее из D::method(A*)


PM MAIL   Вверх
Нитонисе
Дата 3.11.2010, 11:59 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 917
Регистрация: 5.11.2009

Репутация: 2
Всего: 2



Цитата(xvr @  3.11.2010,  11:55 Найти цитируемый пост)
Перенесите разные части того, что нужно исполнять в классе D в классы B и C (в виде виртуальной функции, описанной в классе A), и вызывайте ее из D::method(A*)

Это было бы неудобно, так как метод соотносится с классом D и работает с его данными. Работать данными метода D в классах В и С - как-то не корректно.
PM MAIL   Вверх
xvr
Дата 3.11.2010, 12:08 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Комодератор
Сообщений: 7046
Регистрация: 28.8.2007
Где: Дублин, Ирландия

Репутация: 48
Всего: 223



Цитата(Нитонисе @  3.11.2010,  11:59 Найти цитируемый пост)
Это было бы неудобно,
Тогда штудируйте различный паттерны, что вам больше подойдет. Начать можно с Visitor и MultiMethod

PM MAIL   Вверх
Ответ в темуСоздание новой темы Создание опроса
Правила форума "С++ Builder"
Rrader

Запрещается!

1. Публиковать ссылки на вскрытые компоненты

2. Обсуждать взлом компонентов и делиться вскрытыми компонентами

  • Литературу по С++ Builder обсуждаем здесь
  • Действия модераторов можно обсудить здесь
  • С просьбами о написании курсовой, реферата и т.п. обращаться сюда
  • Настоятельно рекомендуем заглянуть в DRKB (Delphi Russian Knowledge Base) - крупнейший в рунете сборник материалов по Дельфи


Если Вам понравилась атмосфера форума, заходите к нам чаще! С уважением, Rrader.

 
0 Пользователей читают эту тему (0 Гостей и 0 Скрытых Пользователей)
0 Пользователей:
« Предыдущая тема | C++ Builder | Следующая тема »


 




[ Время генерации скрипта: 0.0584 ]   [ Использовано запросов: 22 ]   [ GZIP включён ]


Реклама на сайте     Информационное спонсорство

 
По вопросам размещения рекламы пишите на vladimir(sobaka)vingrad.ru
Отказ от ответственности     Powered by Invision Power Board(R) 1.3 © 2003  IPS, Inc.