Как вы реализуете «делегирование» для классов эффективно в C ++?

В Objective C язык имеет встроенную поддержку делегирования классов другим классам. C ++ не имеет такой возможности (один класс как делегат другого класса) как часть языка. Способ имитировать это разделить декларацию и реализацию следующим образом:

В заголовочном файле хиджры:

class AImpl;

class A
{
public:
A();

void f1();
int f2(int a, int b);
// A's other methods...
private:
AImpl *mImpl;
};

в .CPP (файл реализации):

#include "a.h"
class AImpl
{
public:
AImpl();
// repeating the same method declarations from A
void f1();
int f2(int a, int b);
// AImpl's other methods
};

AImpl::AImpl()
{
}

void AImpl:f1()
{
// actual implemetation
}

int AImpl::f2(int a, int b)
{
// actual implmentation
}

// AImpl's  other methods implementation

A::A()
{
mImpl = new AImpl();
}

// A's "forwarder"
void A::f1()
{
mImpl->f1();
}

int A::f2(int a, int b)
{
return mImpl->f2(a, b);
}

// etc.

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

Вопрос: есть ли лучше или более продуктивный способ достижения этого эффекта с помощью шаблонов или других конструкций языка C ++?

0

Решение

Да, это возможно. Один из возможных примеров:

struct WidgetDelegate
{
virtual ~WidgetDelegate() {}
virtual void onNameChange(std::string newname, std::string oldname) {}
};

class Widget
{
public:
std::shared_ptr<WidgetDelegate> delegate;
explicit Widget(std::string name) : m_name(name){}
void setName(std::string name) {
if (delegate) delegate->onNameChange(name, m_name);
m_name = name;
}
private:
std::string m_name;
};

Использование:

class MyWidgetDelegate : public WidgetDelegate
{
public:
virtual void onNameChange(std::string newname, std::string oldname) {
std::cout << "Widget old name: " << oldname << " and new name: " << newname << std::endl;
}
};

int main()
{
Widget my_widget("Button");
my_widget.delegate = std::make_shared<MyWidgetDelegate>();
my_widget.setName("DoSomeThing");
return 0;
}

Обязательными являются:

#include <string>
#include <iostream>
#include <memory>
0

Другие решения

Вы можете реализовать виртуальный интерфейс в базовом классе.
Однако, если вы действительно хотите делегировать, вы можете перегрузить operator-> делегировать все звонки.

Вам больше не понадобятся методы пересылки:

#include <iostream>
#include <string>

using namespace std;

class AImpl;

class A
{
public:
A();

//Overloading operator -> delegates the calls to AImpl class
AImpl* operator->() const { return mImpl; }

private:
AImpl *mImpl;
};

class AImpl
{
public:
void f1() { std::cout << "Called f1()\n"; }
void f2() { std::cout << "Called f2()\n"; }
};

A::A()
{
mImpl = new AImpl();
}

int main()
{
A a;
a->f1(); //use a as if its a pointer, and call functions of A

A* a1 = new A();
(*a1)->f2();
}
-1

По вопросам рекламы [email protected]