Двойная отправка / мультиметоды в C++

У меня вопрос по двойной отправке C++. В приведенном ниже коде я хочу, чтобы результаты второго набора совпадали с результатами первого набора.

Я не знаю фактического типа (если я не попробую dynamic_cast), но я знаю, что объект унаследован от типа BaseClass. Каков наиболее эффективный (с точки зрения производительности) способ добиться этого?

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

Спасибо за любую помощь.

#include <iostream>
#include <string>
using namespace std;

class BaseClass{
public:
       BaseClass(){}
       virtual void myFunction(){cout << "base myFunction called" << endl;}
};

class Derived1: public BaseClass{
public:
       Derived1():BaseClass(){}
       void myFunction(){cout << "Derived1 myFunction called" << endl;}
};


class Derived2: public BaseClass{
public:
       Derived2():BaseClass(){}
       void myFunction(){cout << "Derived2 myFunction called" << endl;}
};

class Derived3: public BaseClass{
public:
       Derived3():BaseClass(){}
       void myFunction(){cout << "Derived3 myFunction called" << endl;}

};

class Processor{
public:
       Processor(){}
       virtual void processObj(BaseClass* bc){cout << "got a base object" << endl; bc->myFunction();}
       virtual void processObj(Derived1* d1){cout << "got a derived1 object" << endl; d1->myFunction();}
       virtual void processObj(Derived2* d2){cout << "got a derived2 object" << endl; d2->myFunction(); }
};


int main() {
   BaseClass *bcp=new BaseClass();
   Derived1 *dc1p=new Derived1();   
   Derived2 *dc2p=new Derived2();
   Derived3 *dc3p=new Derived3();

   Processor p;//can also use Processor* p = new Processor()

   //first set results
   p.processObj(bcp);
   p.processObj(dc1p);
   p.processObj(dc2p);
   p.processObj(dc3p);

   BaseClass *bcp1=bcp;
   BaseClass *dc1p1=dc1p;   
   BaseClass *dc2p1=dc2p;
   BaseClass *dc3p1=dc3p;

   //second set results
   p.processObj(bcp1);
   p.processObj(dc1p1);
   p.processObj(dc2p1);
   p.processObj(dc3p1);

   return 0;
}

... отредактирован, чтобы код отображался в блоке кода

Mr Fooz 10.01.2009 00:44
Стоит ли изучать PHP в 2026-2027 годах?
Стоит ли изучать PHP в 2026-2027 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
9
1
5 856
4

Ответы 4

Вам нужно будет поместить виртуальный метод в BaseClass для вызова processObj из производных классов.

class BaseClass{
public:
       BaseClass(){}
       virtual void ProcessThis(Processor &p) { p.processObj(this); }
       virtual void myFunction(){cout << "base myFunction called" << endl;}
};

class Derived1: public BaseClass{
public:
       Derived1():BaseClass(){}
       void ProcessThis(Processor &p) { p.processObj(this); }
       void myFunction(){cout << "Derived1 myFunction called" << endl;}
};

class Derived2: public BaseClass{
public:
       Derived2():BaseClass(){}
       void ProcessThis(Processor &p) { p.processObj(this); }
       void myFunction(){cout << "Derived2 myFunction called" << endl;}
};

class Derived3: public BaseClass{
public:
       Derived3():BaseClass(){}
       void ProcessThis(Processor &p) { p.processObj(this); }
       void myFunction(){cout << "Derived3 myFunction called" << endl;}

};

class Processor{
public:
       Processor(){}
       virtual void processObj(BaseClass* bc){cout << "got a base object" << endl; bc->myFunction();}
       virtual void processObj(Derived1* d1){cout << "got a derived1 object" << endl; d1->myFunction();}
       virtual void processObj(Derived2* d2){cout << "got a derived2 object" << endl; d2->myFunction(); }
};

int main() {
   BaseClass *bcp=new BaseClass();
   Derived1 *dc1p=new Derived1();   
   Derived2 *dc2p=new Derived2();
   Derived3 *dc3p=new Derived3();

   Processor p;//can also use Processor* p = new Processor()

   //first set results
   bcp->ProcessThis(p);
   dc1p->ProcessThis(p);
   dc1p->ProcessThis(p);
   dc3p->ProcessThis(p);

   BaseClass *bcp1=bcp;
   BaseClass *dc1p1=dc1p;   
   BaseClass *dc2p1=dc2p;
   BaseClass *dc3p1=dc3p;

   //second set results
   bcp1->ProcessThis(p);
   dc1p1->ProcessThis(p);
   dc2p1->ProcessThis(p);
   dc3p1->ProcessThis(p);

   Processor p2;
   bcp1->ProcessThis(p2);
   dc1p1->ProcessThis(p2);
   dc2p1->ProcessThis(p2);
   dc3p1->ProcessThis(p2);

   return 0;
}

По сути, вам нужен шаблон Visitor, но только с одним типом посетителей. Вы можете сэкономить некоторые усилия в будущем и превратить Processor в абстрактный класс и реализовать один конкретный класс ProcessorImpl, что упрощает добавление другого класса процессора в будущем, или вы можете подождать, пока возникнет такая ситуация, и оставить все как есть на данный момент .

Шаблон посетителя предназначен только для обработки таких ситуаций.

Вы пропустили "двойную" часть двойной рассылки.

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

По сути, каждому объекту нужен виртуальный метод processMe(Processor &p), и процессор вызывает его. Реализация processMe вызывает p.processObject(this). Но на этот раз у «этого» есть известный тип! Таким образом, вместо бесконечной рекурсии вы получаете правильный proceessObject, называемый

Большое спасибо. Это решило мою проблему, и я понимаю, что такое двойная отправка! Вот полный код для потомков (кто-нибудь, пожалуйста, научите меня, как правильно форматировать):

#include <iostream>
using namespace std;

class BaseClass;
class Derived1;
class Derived2;
class Derived3;

class Processor {
public:
       Processor(){}
       virtual void processObj(BaseClass* bc);
       virtual void processObj(Derived1* d1);
       virtual void processObj(Derived2* d2);
};


class BaseClass{
public:
       BaseClass(){}
       virtual void ProcessThis(Processor &p) { p.processObj(this); }
       virtual void myFunction(){cout << "base myFunction called" << endl;}
};

class Derived1: public BaseClass{
public:
       Derived1():BaseClass(){}
       void ProcessThis(Processor &p) { p.processObj(this); }
       void myFunction(){cout << "Derived1 myFunction called" << endl;}
};

class Derived2: public BaseClass{
public:
       Derived2():BaseClass(){}
       void ProcessThis(Processor &p) { p.processObj(this); }
       void myFunction(){cout << "Derived2 myFunction called" << endl;}
};

class Derived3: public BaseClass{
public:
       Derived3():BaseClass(){}
       void ProcessThis(Processor &p) { p.processObj(this); }
       void myFunction(){cout << "Derived3 myFunction called" << endl;}

};

void Processor::processObj(BaseClass* bc){cout << "got a base object" << endl; bc->myFunction();}
void Processor::processObj(Derived1* d1){cout << "got a derived1 object" << endl; d1->myFunction();}
void Processor::processObj(Derived2* d2){cout << "got a derived2 object" << endl; d2->myFunction(); }


int main() {
   BaseClass *bcp=new BaseClass();
   Derived1 *dc1p=new Derived1();   
   Derived2 *dc2p=new Derived2();
   Derived3 *dc3p=new Derived3();

   Processor p;//can also use Processor* p = new Processor()

   //first set results

   bcp->ProcessThis(p);
   dc1p->ProcessThis(p);
   dc2p->ProcessThis(p);
   dc3p->ProcessThis(p);

   BaseClass *bcp1=bcp;
   BaseClass *dc1p1=dc1p;   
   BaseClass *dc2p1=dc2p;
   BaseClass *dc3p1=dc3p;

   //second set results

   bcp1->ProcessThis(p);
   dc1p1->ProcessThis(p);
   dc2p1->ProcessThis(p);
   dc3p1->ProcessThis(p);

   Processor p2;
   bcp1->ProcessThis(p2);
   dc1p1->ProcessThis(p2);
   dc2p1->ProcessThis(p2);
   dc3p1->ProcessThis(p2);

   return 0;
}

Другие вопросы по теме