How do you implement "delegation" for classes efficiently in C++? - c++

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?

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>

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

Related

List of multiple class to run same function name C++ [duplicate]

This question already has answers here:
How to store object of different class types into one container in modern c++?
(2 answers)
Closed 3 years ago.
I have multiple classes with same function as below
class A
{
void display()
{
// display something
}
};
class B
{
void display()
{
// display something two
}
};
I want to store difference class at a list or a vector and loop to call the same function with same name
int main()
{
A * a;
B * b;
//list or vector to store object
std::vector < Something that can store different class > listofclass;
listofclass.emplace_back(a);
listofclass.emplace_back(b);
for (int i = 0; i < listofclass.size(); i++)
{
listofclass[i].display();
}
}
Is that possible to do like this?
Because there is separate classes, having different purpose, and now i try to group them together
Or there is other alternative way to achieve something like this
If you control the definition of A and B, you can write a common base class, and have them inherit it.
class can_display {
public:
virtual void display() = 0;
virtual ~can_display() = default;
};
class A : public can_display
{
void display() override
{
// display something
}
};
class B : public can_display
{
void display() override
{
// display something two
}
};
int main()
{
A a;
B b;
std::vector<can_display *> displayables;
displayables.push_back(&a);
displayables.push_back(&b);
for (can_display * displayable : displayables)
{
displayable->display();
}
}
As an alternative to changing the definition of A and B to inherit from a common base, you can have a wrapper that inherits.
template <typename T>
class can_display_impl {
T * wrapped;
public:
can_display_impl(T * wrapped) : wrapped(wrapped) {}
void display() override { wrapped->display(); }
}
template <typename T>
std::unique_ptr<can_display> make_can_display(T & wrapped) {
return std::make_unique<can_display_impl<T>>(&wrapped);
}
int main()
{
A a;
B b;
std::vector<std::unique_ptr<can_display>> displayables;
displayables.emplace_back(make_can_display(a));
displayables.emplace_back(make_can_display(b));
for (auto & displayable : displayables)
{
displayable->display();
}
}
You have two solutions for this problem:
Use inheritance and just make a abstract class that will be a interface for your classes. In class A and class B just inherit from that interface and in std::vector hold pointer to base class.
#include <vector>
#include <iostream>
#include <memory>
class Interface_display {
public:
virtual void display() = 0;
virtual ~Interface_display(){};
};
class A : public Interface_display
{
public:
void display() override
{
std::cout << "Display from A\n";
}
~A() override = default;
};
class B : public Interface_display
{
public:
void display() override
{
std::cout << "Display from B\n";
}
~B() override = default;
};
int main(void)
{
std::vector<std::unique_ptr<Interface_display>> v;
v.emplace_back(std::make_unique<A>());
v.emplace_back(std::make_unique<B>());
for (const auto &element: v) {
element->display();
}
}
And if you are using c++17, you could use std::variant and wrap objects of your class to std::variant:
#include <vector>
#include <iostream>
#include <variant>
class A
{
public:
void display()
{
std::cout << "Display from A\n";
}
};
class B
{
public:
void display()
{
std::cout << "Display from B\n";
}
};
int main(void)
{
using variant_t = std::variant<A, B>;
std::vector<variant_t> v;
v.emplace_back(A());
v.emplace_back(B());
for (auto &element: v) {
std::visit([](auto &x) { x.display(); }, element);
}
}
https://wandbox.org/permlink/8VBmziWzafbPZk99
A way to solve this problem is by using polymorphism. You make a superclass, which contains a pure virtual version of this function and let both A and B inherit from this class. By doing this, you can dynamic_cast any pointer of type A or B to a superclass type, on which you have defined the display function.
This will get you something like this
class C {
public:
virtual void display() = 0;
virtual ~C() = default;
};
class A : public C {
public:
void display() override {
std::cout << "A" << std::endl;
};
~A() override = default;
};
class B : public C {
public:
void display(){
std::cout << "B" << std::endl;
};
~B() override = default;
};
So you can do:
C* c = new A();
// You can put the types of C* in the same list, and iterate over this list and do on each element
c->display();
delete c;

Alternative to virtual variables

I have two classes, Base and Derived. Derived inherits from Base and additionally includes several functions and variables -- therefore the need to have two separate classes. However, they do share one function, run.
In the example below I have to pass an argument to run in order to execute read - this argument depends on which class the object refers to. Is it possible to write a generic version of read such that the program automatically uses vars_Base or vars_Derived depending on which object calls run?
#include <iostream>
#include <fstream>
#include <string>
#include <vector>
class Base
{
protected:
void read(std::vector<std::string>);
public:
void run(std::vector<std::string> vars) { read(vars); }
std::vector<std::string> vars_Base;
};
void Base::read(std::vector<std::string> int_vars)
{
for (auto int_vars_it : int_vars)
{
std::cout << int_vars_it << "\n";
}
}
class Derived : public Base
{
protected:
public:
std::vector<std::string> vars_Derived;
///Here are other functions only known to Derived, not Base
};
int main()
{
Base b;
b.vars_Base.push_back("aB");
b.vars_Base.push_back("bB");
b.vars_Base.push_back("cB");
b.run(b.vars_Base);
Derived d;
d.vars_Derived.push_back("aD");
d.vars_Derived.push_back("bD");
d.vars_Derived.push_back("cD");
d.run(d.vars_Derived);
return 0;
}
Is that the result you want to get?
class Base
{
protected:
using vars_type = std::vector<std::string>;
private:
vars_type vars_Base;
protected:
virtual vars_type& get_vars() {
return vars_Base;
}
public:
void push_back(const std::string& str) {
get_vars().push_back(str);
}
void run()
{
for (auto int_vars_it : get_vars()) {
std::cout << int_vars_it << " ";
}
}
};
class Derived : public Base
{
private:
vars_type vars_Derived;
protected:
vars_type& get_vars() override {
return vars_Derived;
}
public:
///Here are other functions only known to Derived, not Base
};
int main(int argc, char* argv[])
{
Base b;
b.push_back("aB");
b.push_back("bB");
b.push_back("cB");
b.run(); // prints aB bB cB
std::cout << std::endl;
Derived d;
d.push_back("aD");
d.push_back("bD");
d.push_back("cD");
d.run(); // prints aD bD cD
return 0;
}
If so then the explanation is next: there is no such thing as a "virtual variable", but there are virtual functions. You can use virtual functions as "internal accessors" for your member variables. Although, Derived class contains both vars_Base and vars_Derived, get_vars() lets you override access to appropriate instance of vars.
Hope you'll find it helpful.
You can make use of virtual functions to solve your problem, without the use for generics.
Here is a solution using virtual functions (applied to your sample code) :
#include <iostream>
#include <fstream>
#include <string>
#include <vector>
class Base
{
protected:
void read(std::vector<std::string>);
public:
virtual void run() { read(vars_Base); }
std::vector<std::string> vars_Base;
};
void Base::read(std::vector<std::string> int_vars)
{
for (auto int_vars_it : int_vars)
{
std::cout << int_vars_it << "\n";
}
}
class Derived : public Base
{
protected:
public:
void run() override { read(vars_Derived); }
std::vector<std::string> vars_Derived;
///Here are other functions only known to Derived, not Base
};
int main()
{
Base b;
b.vars_Base.push_back("aB");
b.vars_Base.push_back("bB");
b.vars_Base.push_back("cB");
b.run();
Derived d;
d.vars_Derived.push_back("aD");
d.vars_Derived.push_back("bD");
d.vars_Derived.push_back("cD");
d.run();
return 0;
}
This solution allows to encapsulate vars_Base and vars_Derived inside the classes.
Hope this helps.

C++ class definition split into two headers?

Is it possible in C++ to split the definition of class members in two headers? What would be the appropriate way to code it?
For instance:
a1.h
class A {
public:
int var;
void foo1(int b);
}
a1.cpp
#include "a1.h"
void A::foo1(int b) {
cout << b;
}
a2.h
[extend] class A {
public:
void foo2(double c);
}
a2.cpp
#include "a2.h"
void A::foo2(double c) {
cout << c;
}
You can't extend a class that way, but you can use the pimpl pattern:
class A {
public:
void foo1(int b);
private:
AImpl* pimpl;
}
and then have AImpl.h and AImpl.cpp that hides all the private details.

Can you create a std::map of inherited classes?

I'm wondering if it's possible to create a map of pointers of inherited classes. Here's an example of what I'm trying to do:
#include <string>
#include <map>
using namespace std;
class BaseClass
{
string s;
};
class Derived1 : public BaseClass
{
int i;
};
class Derived2 : public Derived1
{
float f;
};
// Here's what I was trying, but isn't working
template<class myClass>
map<string, myClass>m;
int main()
{
// Add BaseClasses, Derived1's, and/or Derived2's to m here
return 0;
}
The errors I get are:
main.cpp(23): error C2133: 'm' : unknown size
main.cpp(23): error C2998: 'std::map<std::string,myClass>m' : cannot be a template definition
I get why I'm getting this error, but I'm wondering if it's possible to create a map that can hold different levels of inherited classes? If not, is it possible to create some sort of management system that can hold various class types? Or would I have to make different maps/vectors/arrays/etc. for each type of class?
Yes you can store inherited classes in map, but pointers to them, not objects themselves. Here's a short example (it lacks memory management on pointers)
#include <iostream>
#include <string>
#include <map>
#include <utility>
using namespace std;
class BaseClass
{
string s;
public:
BaseClass() { s = "BaseClass";}
virtual void print()
{
cout << s << std::endl;
}
};
class Derived1 : public BaseClass
{
int i;
public:
Derived1() { i = 10; }
void print()
{
cout << i << std::endl;
}
};
class Derived2 : public Derived1
{
float f;
public:
Derived2() { f = 4.3;}
void print()
{
cout << f << std::endl;
}
};
int main()
{
map<string, BaseClass*>m;
m.insert(make_pair("base", new BaseClass()));
m.insert(make_pair("d1", new Derived1()));
m.insert(make_pair("d2", new Derived2()));
m["base"]->print();
m["d1"]->print();
m["d2"]->print();
return 0;
}
First things first:
template<class myClas>
map<string, myClass> m;
This is not valid C++ and could only mean something like a template alias, but I believe, that is not what you are looking for.
Storing polymorphic objects in C++ is complicated by slicing (constructing a value of the base type from a value of a derived type). Dynamic polymorphism can only be handled through references or pointers. You could potentially use std::ref or boost::ref for situations in which the map will only be passed down the callstack, but this requires some care. Often, storing pointers to the base is the way to go: std::map<std::string, base*>. Managing deallocation yourself is rather tedious and either std::map<std::string, std::unique_ptr> or std::map<std::string, std::shared_ptr> are preferred, depending if you need shared semantics or not.
Basic example. Someone should replace this with something more meaningful.
#include <memory>
#include <string>
#include <map>
#include <iostream>
class animal
{
public:
virtual ~animal() {};
virtual void make_sound() const = 0;
};
class dog : public animal
{
public:
void make_sound() const { std::cout << "bark" << std::endl; }
};
class bird : public animal
{
public:
void make_sound() const { std::cout << "chirp" << std::endl; }
};
int main()
{
std::map<std::string, std::unique_ptr<animal>> m;
m.insert(std::make_pair("stupid_dog_name", new dog));
m.insert(std::make_pair("stupid_bird_name", new bird));
m["stupid_dog_name"]->make_sound();
return 0;
}
You may have template on classes and functions, but not on instances.
You should stick to the map to BaseClass*'es.
Below is the expansion of solution suggested by anton.
#include <iostream>
#include <string>
#include <map>
#include <utility>
using namespace std;
class BaseClass
{
string s;
public:
BaseClass() { s = "BaseClass";}
virtual ~ BaseClass(){}
virtual void print()=0;
};
class Derived1 : public BaseClass
{
int i;
public:
Derived1() { i = 10; }
void print()
{
cout << i << std::endl;
}
};
class Derived2 : public Derived1
{
float f;
public:
Derived2() { f = 4.3;}
void print()
{
cout << f << std::endl;
}
};
class factory
{
map<string, BaseClass*>m;
BaseClass* obj;
public:
factory()
{
obj=NULL;
}
BaseClass* FindType(string s);
void AddType(string s,BaseClass *obj);
void deleter();
~factory(){cout<<"deleting objects from map"<<endl;
deleter();
}
};
void factory :: AddType(string s,BaseClass* obj)
{
m.insert(make_pair(s,obj ));
}
void factory ::deleter ()
{
for (auto pObj = m.begin( );
pObj != m.end( ); ++pObj) {
delete pObj->second;
}
m.clear( );
}
BaseClass* factory::FindType(string s)
{
if(m.find(s)!=m.end())
{
return m[s];
}
return NULL;
}
int main()
{
BaseClass* obj;
factory fact_obj;
fact_obj.AddType("d1",new Derived1());
fact_obj.AddType("d2",new Derived2());
obj=fact_obj.FindType("d1");
if(obj!=NULL)
{
obj->print();
}
obj=fact_obj.FindType("d2");
if(obj!=NULL)
{
obj->print();
}
return 0;
}

Nested Class member function can't access function of enclosing class. Why?

Please see the example code below:
class A
{
private:
class B
{
public:
foobar();
};
public:
foo();
bar();
};
Within class A & B implementation:
A::foo()
{
//do something
}
A::bar()
{
//some code
foo();
//more code
}
A::B::foobar()
{
//some code
foo(); //<<compiler doesn't like this
}
The compiler flags the call to foo() within the method foobar(). Earlier, I had foo() as private member function of class A but changed to public assuming that B's function can't see it. Of course, it didn't help. I am trying to re-use the functionality provided by A's method. Why doesn't the compiler allow this function call? As I see it, they are part of same enclosing class (A). I thought the accessibility issue for nested class meebers for enclosing class in C++ standards was resolved.
How can I achieve what I am trying to do without re-writing the same method (foo()) for B, which keeping B nested within A?
I am using VC++ compiler ver-9 (Visual Studio 2008). Thank you for your help.
foo() is a non-static member function of A and you are trying to call it without an instance.
The nested class B is a seperate class that only has some access privileges and doesn't have any special knowledge about existing instances of A.
If B needs access to an A you have to give it a reference to it, e.g.:
class A {
class B {
A& parent_;
public:
B(A& parent) : parent_(parent) {}
void foobar() { parent_.foo(); }
};
B b_;
public:
A() : b_(*this) {}
};
This is an automagic, albeit possibly nonportable trick (worked on VC++ since 6.0 though). Class B has to be a member of class A for this to work.
#ifndef OUTERCLASS
#define OUTERCLASS(className, memberName) \
reinterpret_cast<className*>(reinterpret_cast<unsigned char*>(this) - offsetof(className, memberName))
#endif
class A
{
private:
class B
{
public:
void foobar() {
A* pA = OUTERCLASS(A, m_classB);
pA->foo();
}
} m_classB;
public:
foo();
bar();
};
Basically what Georg Fritzsche said
#include <iostream>
#include <cstring>
using namespace std;
class A
{
private:
class B
{
A& parent_;
public:
//B(); //uncommenting gives error
~B();
B(A& parent) : parent_(parent) {}
void foobar()
{
parent_.foo();
cout << "A::B::foo()" <<endl;
}
const std::string& foobarstring(const std::string& test) const
{
parent_.foostring(test); cout << "A::B::foostring()" <<endl;
}
};
public:
void foo();
void bar();
const std::string& foostring(const std::string& test) const;
A();
~A(){};
B b_;
};
//A::B::B() {}; //uncommenting gives error
A::B::~B(){};
A::A():b_(*this) {}
void A::foo()
{
cout << "A::foo()" <<endl;
}
const std::string& A::foostring(const std::string& test) const
{
cout << test <<endl;
return test;
}
void A::bar()
{
//some code
cout << "A::bar()" <<endl;
foo();
//more code
}
int main(int argc, char* argv[])
{
A a;
a.b_.foobar();
a.b_.foobarstring("hello");
return 0;
}
If you uncomment the default B constructor you would get an error
If you want to reuse functionality from A then you should inherit from A not nest B inside it.
Combining Igor Zevaka's and enthusiasticgeek's answers. Also, using reinterpret_cast for calculating offset (If you create class member variable using new keyword):
#include <iostream>
#include <cstring>
using namespace std;
template < typename T, typename U > constexpr size_t offsetOf(U T:: *member)
{
return (char*) &((T*) nullptr->*member) - (char*) nullptr;
}
class A
{
private:
class B
{
public:
B(string message);
~B();
void foobar()
{
A *pA = reinterpret_cast<A*> (reinterpret_cast< unsigned char*> (this) - offsetOf(&A::b_));
pA->foo();
pA->bar();
std::cout << "DONE!";
}
};
public:
void foo();
void bar();
A();
~A() {};
B* b_ = new B("Hello World!");
};
A::A()
{
cout << "A constructor\n";
};
A::B::B(string message) {
cout << "B constructor\n";
cout << "Message = " << message << "\n";
};
A::B::~B() {};
void A::foo()
{
cout << "A::foo()" << endl;
}
void A::bar()
{
cout << "A::bar()" << endl;
foo();
}
int main(int argc, char *argv[])
{
A* a = new A();
a->b_->foobar();
return 0;
}
Output:
B constructor
Message = Hello World!
A constructor
A::foo()
A::bar()
A::foo()
DONE!
References:
https://stackoverflow.com/a/10607424/9524565
https://stackoverflow.com/a/3058382/9524565
https://stackoverflow.com/a/20141143/9524565