0

In Objective C the language has built in support for delegation of classes to other classes. C++ does not have such feature (one class as a delegate of another class) as part of the language. A way to mimic that is to separate declaration and implementation this way:

In header file a.h:

class AImpl;

class A
{
public:
     A();

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

In the .cpp (implementation file):

#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.

This requires manually creating all "forwarder" functions in the class that would delegate to another class to do the actual work. Tedious, to say the least.

The question is: is there a better or more productive way to achieve this effect using templates or other C++ langage constructs?

atai
  • 43
  • 5
  • Instead of all this forwarding you can just declare a pure interface in the header, plus declaration of a factory function. In the implementation file a class implementing the interface, and implementation of the factory. Assuming it's not the intent that client code should be able to meaningfully extend the class. – Cheers and hth. - Alf Jan 31 '16 at 06:28
  • I don't think there is but I will wait for someone more knowledgeable than me to correct me. – R Sahu Jan 31 '16 at 06:29
  • 1
    I was about to write a complete list on how to delegate function in C++ , but I found that someone already did that: http://stackoverflow.com/questions/9568150/what-is-a-c-delegate voting to close as duplicate – David Haim Jan 31 '16 at 10:35
  • I clarified the question--I am especially interested in class level delegation, not function level delegation. – atai Feb 01 '16 at 04:59

2 Answers2

0

Yes it's possible. One of possible examples is:

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;
};

Usage:

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;
}

Required includes are:

#include <string>
#include <iostream>
#include <memory>
Bagobor
  • 51
  • 3
-1

You can implement a virtual interface in the base class.
However, if you really want to delegate, then you can overload the operator-> to delegate all calls.
You won't need anymore the forwarding methods:

#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();
}
skypjack
  • 49,335
  • 19
  • 95
  • 187
Amitoj
  • 108
  • 3
  • To be honest, using `a` _as if it's a pointer_ when it is not is a bit counterintuitive and I guess it won't help the reader/maintainer of the code. My two cents. – skypjack Jan 31 '16 at 10:58