I have two variants of the same method. I also have an instance of a base class type, but I don't know what specific class it is an instance of. I now want to automatically select the appropriate method depending on the actual type of the object. It seems impossible though and the only solution I can come up with is to check all possibilities by casting.
There has to be a nicer solution though.
Here is my minimal example:
// Example program
#include <iostream>
#include <string>
#include <memory>
class A
{
public:
virtual void bar() const = 0;
};
class B : public A
{
public:
void bar() const
{
std::cout << "B.bar()" << std::endl;
}
};
class C : public A
{
public:
void bar() const
{
std::cout << "C.bar()" << std::endl;
}
};
class Z
{
public:
Z(int variable) : m_variable(variable) {};
void foo(std::shared_ptr<B> b)
{
std::cout << "Calling foo(B) method! " << m_variable << std::endl;
b->bar();
}
void foo(std::shared_ptr<C> c)
{
std::cout << "Calling foo(C) method!" << m_variable << std::endl;
c->bar();
}
private:
int m_variable;
};
int main()
{
std::shared_ptr<A> b(new B());
Z z(42);
//z.foo(b); // This doesn't work
// But this does
std::shared_ptr<B> b_cast = std::dynamic_pointer_cast<B>(b);
if (b_cast.get())
z.foo(b_cast);
}
http://cpp.sh/9fqne
At the moment I have to resort to dynamic_pointer_cast, but I find it kinda ugly and not very maintainable.
I also don't want to add the functionality of foo() to the classes B and C, because those are small independent data structures on which many other classes operate.
Thank you very much!
EDIT: In the original post I simplified a bit too much. The new example should clear things up.
Add a pure virtual function foo() to your base class and override in subsequent derived classes. Then have your global function foo() (which has nothing to do with member functions with the same name) accept a reference to std::shared_ptr const as a parameter:
#include <iostream>
#include <memory>
class A{
public:
virtual void foo() = 0;
};
class B : public A{
public:
void foo() override{
std::cout << "Calling foo(B) method!" << std::endl;
}
};
class C : public A{
public:
void foo() override{
std::cout << "Calling foo(C) method!" << std::endl;
}
};
void foo(const std::shared_ptr<A>& param){
param->foo();
}
int main(){
std::shared_ptr<A> b = std::make_shared<B>();
std::shared_ptr<A> c = std::make_shared<C>();
foo(b);
foo(c);
}
As BoBTFish pointed out, the visitor pattern is a potential solution for this problem:
// Example program
#include <iostream>
#include <string>
#include <memory>
class B;
class C;
class Visitor
{
public:
virtual void visit(B* b) const = 0;
virtual void visit(C* b) const = 0;
};
class A
{
public:
virtual void bar() const = 0;
virtual void accept(const Visitor* visitor) = 0;
};
class B : public A
{
public:
void bar() const
{
std::cout << "B.bar()" << std::endl;
}
void accept(const Visitor* visitor)
{
visitor->visit(this);
}
};
class C : public A
{
public:
void bar() const
{
std::cout << "C.bar()" << std::endl;
}
void accept(const Visitor* visitor)
{
visitor->visit(this);
}
};
class Z : public Visitor
{
public:
Z(int variable) : m_variable(variable) {};
void visit(B* b) const
{
std::cout << "Calling foo(B) method! " << m_variable << std::endl;
b->bar();
}
void visit(C* c) const
{
std::cout << "Calling foo(C) method!" << m_variable << std::endl;
c->bar();
}
private:
int m_variable;
};
int main()
{
std::shared_ptr<A> b(new B());
Z z(42);
b->accept(&z);
}
http://cpp.sh/2vah5
Thank you very much!
Related
I have two classes B andY which I cannot change or edit by requirement. They have functions doing the same thing but with different names.
I want to a have a common interfaces with selecting the class at run time depending on the some input variable as described in the code below. I am not sure which design pattern should I use. How to create WrapperYB class which selects Y::show or B::showing depending on the object created.
class A
{
public:
A() {}
virtual ~A();
virtual void show() { cout << "show A" << endl;}
};
class B:A
{
public:
B() {}
virtual ~B();
virtual void show() { cout << "show B" << endl;}
};
class X
{
char m_i;
public:
Y() { m_i = 'X';}
virtual void showing() { cout << "showing " << m_i << endl;}
};
class Y:X
{
public:
Y() { m_i = 'Y';}
virtual void showing() { cout << "showing " << m_i << endl;}
};
class WrapperYB
{
// to be implemented
public:
explicit WrapperYB(const int& type);
void show();
};
int main(){
WrapperYB objY(1);
objY.show(); // must call Y::showing
WrapperYB objB(0);
objB.show(); // must call B::show
}
If your compiler supports the C++17 Standard, you could try this solution using std::variant. This is a similar idea to the solution in #Nicolas's answer, but variant will take care of the implementation details for you, won't use dynamic memory allocation, and has support for additional things like copy and assignment.
#include <variant>
#include <utility>
#include <type_traits>
class WrapperYB {
public:
using variant_type = std::variant<Y, B>;
template <typename... Args,
std::enable_if_t<std::is_constructible_v<variant_type, Args...>>* = nullptr>
WrapperYB(Args&& ... args) : m_variant(std::forward<Args>(args)...) {}
variant_type& variant() noexcept { return m_variant; }
const variant_type& variant() const noexcept { return m_variant; }
void show()
{ std::visit(ShowImpl{}, m_variant); }
private:
struct ShowImpl {
void operator() (Y& y) const { y.showing(); }
void operator() (B& b) const { b.show(); }
};
variant_type m_variant;
};
See the full working example on coliru.
You might generalize the wrapper by letting it contain a std::unique_ptr<A> or std::unique_ptr<X> instead.
I'm proposing this:
#include <iostream>
using namespace std;
class A
{
public:
A() {}
virtual ~A() {}
virtual void show() { cout << "show A" << endl;}
};
class B:A
{
public:
B() {}
virtual ~B() {}
virtual void show() { cout << "show B" << endl;}
};
class X
{
protected:
char m_i;
public:
X () { m_i = 'X';}
virtual void showing() { cout << "showing " << m_i << endl;}
};
class Y:X
{
public:
Y() { m_i = 'Y';}
virtual void showing() { cout << "showing " << m_i << endl;}
};
class WrapperYB
{
public:
enum class Which { B, Y };
public:
explicit WrapperYB (int n)
: which(Which(n))
{
switch (which)
{
case Which::B: ptr.b = new B; break;
case Which::Y: ptr.y = new Y; break;
}
}
~WrapperYB ()
{
switch (which)
{
case Which::B: delete ptr.b; break;
case Which::Y: delete ptr.y; break;
}
}
WrapperYB (const WrapperYB&) = delete;
WrapperYB& operator = (const WrapperYB&) = delete;
public:
void show()
{
switch (which)
{
case Which::B: ptr.b->show() ; break;
case Which::Y: ptr.y->showing(); break;
}
}
private:
Which which;
union {
Y* y;
B* b;
} ptr;
};
int main(){
WrapperYB objY(1);
objY.show(); // must call Y::showing
WrapperYB objB(0);
objB.show(); // must call B::show
}
It's not a "Vanilla" design pattern, I don't think, and more of combination of adapter and discriminated union.
Note that WrapperYB cannot be copied or assigned, as is.
You can use a standard virtual dispatch method with an abstract base adaptor class and subclasses for each object type needed. Create the object with a factory method.
#include <memory>
//pre-defined structures Y, B
struct Y
{
Y(){}
~Y(){}
void show(){}
};
struct B
{
B(){}
~B(){}
void showing(){}
};
// Abstract adaptor base class.
struct Adaptor
{
virtual void show() = 0;
};
// A subclass of Adaptor for each type of object to be wrapped.
struct Adaptor_Y: Adaptor
{
Adaptor_Y(): y(){}
void show() override
{
y.show();
}
private:
Y y;
};
struct Adaptor_B: Adaptor
{
Adaptor_B(): b(){}
void show() override
{
b.showing();
}
private:
B b;
};
// Factory method constructs the proper object and returns a pointer.
std::unique_ptr<Adaptor> get_adaptor(int flag)
{
if(flag == 0)
{
return std::make_unique<Adaptor_B>();
}
else if(flag == 1)
{
return std::make_unique<Adaptor_Y>();
}
else throw std::runtime_error("Invalid flag value");
}
I have been looking for a way to use both templating and polymorphism at the same time. Here's a simplified version of my problem:
#include <iostream>
#include <vector>
using std::cout;
using std::endl;
//*******************************************************************
//*******************************************************************
struct DerivedStuff1
{
static void eval() { cout << "evaluating DerivedStuff1" << endl; }
};
struct DerivedStuff2
{
static void eval() { cout << "evaluating DerivedStuff2" << endl; }
};
//*******************************************************************
//*******************************************************************
class BaseClass
{
public:
template<typename StuffType> virtual void eval() const = 0;
};
class DerivedClass1 : public BaseClass
{
public:
template<typename StuffType> virtual void eval() const
{
std::cout << "We are in DerivedClass1: ";
StuffType::eval();
}
};
class DerivedClass2 : public BaseClass
{
public:
template<typename StuffType> virtual void eval() const
{
std::cout << "We are in DerivedClass2: ";
StuffType::eval();
}
};
int main()
{
BaseClass* c1 = new DerivedClass1;
c1->eval<DerivedStuff1>();
c1->eval<DerivedStuff2>();
BaseClass* c2 = new DerivedClass2;
c2->eval<DerivedStuff1>();
c2->eval<DerivedStuff2>();
return 0;
}
This code does not compile because virtual template functions are not allowed in C++. I found a few approaches to tackle this problem (CRTP, etc.) but none of them were really satisfying. Is there no elegant way to get around that issue?
The visitor pattern turns run-time polymorphism on its side and makes runtime-polymorphic function templates possible. It has other legitimate uses apart from templatisation, so I guess you can call it somewhat elegant.
Your example can look as follows:
#include <iostream>
class DerivedStuff1 {
public:
static void eval() { std::cout << "Evaluating DerivedStuff1\n"; }
};
class DerivedStuff2 {
public:
static void eval() { std::cout << "Evaluating DerivedStuff2\n"; }
};
class DerivedClass1; class DerivedClass2;
class BaseClassVisitor {
public:
virtual void visit(DerivedClass1&) = 0;
virtual void visit(DerivedClass2&) = 0;
};
class BaseClass {
public:
virtual void accept(BaseClassVisitor& v) = 0;
};
class DerivedClass1 : public BaseClass
{
public:
virtual void accept(BaseClassVisitor& v) { v.visit(*this); }
};
class DerivedClass2 : public BaseClass
{
public:
virtual void accept(BaseClassVisitor& v) { v.visit(*this); }
};
template <typename StuffType>
class EvalVisitor : public BaseClassVisitor
{
virtual void visit(DerivedClass1&) {
std::cout << "We are in DerivedClass1: ";
StuffType::eval();
}
virtual void visit(DerivedClass2&) {
std::cout << "We are in DerivedClass2: ";
StuffType::eval();
}
};
int main()
{
EvalVisitor<DerivedStuff1> e1;
EvalVisitor<DerivedStuff2> e2;
BaseClass* c1 = new DerivedClass1;
c1->accept(e1);
c1->accept(e2);
BaseClass* c2 = new DerivedClass2;
c2->accept(e1);
c2->accept(e2);
return 0;
}
Demo
Of course all shortcomings of Visitor apply here.
You could reinvent the vtable and resolve the function pointer at run time. You will, however, have to explicitely instantiate the template on the derived class, but I don't see any approach to this that won't require that.
Quick and dirty example:
#include <map>
#include <iostream>
class Base {
public:
typedef void (Base::*eval_ptr)();
using eval_vtable = std::map<std::type_index, eval_ptr>;
Base(eval_vtable const& eval_p) : eval_ptrs(eval_p) {}
template<typename T>
void eval() {
auto handler = eval_ptrs.find(type_index(typeid(T)));
if(handler != eval_ptrs.end()) {
auto handler_ptr = handler->second;
(this->*handler_ptr)();
}
}
eval_vtable const& eval_ptrs;
};
class Derived : public Base {
public:
Derived()
: Base(eval_functions) {}
template<typename T>
void eval_impl() {
std::cout << typeid(T).name() << "\n";
}
static eval_vtable eval_functions;
};
Base::eval_vtable Derived::eval_functions = {
{ type_index(typeid(int)), eval_ptr(&Derived::eval_impl<int>) },
{ type_index(typeid(float)), eval_ptr(&Derived::eval_impl<float>) },
{ type_index(typeid(short)), eval_ptr(&Derived::eval_impl<short>) },
};
int main(int argc, const char* argv[]) {
Derived x;
Base * x_as_base = &x;
x_as_base->eval<int>(); // calls Derived::eval_impl<int>()
return 0;
}
This won't be exactly fast, but it will give you the closest thing to templated virtual functions that I can think of.
Edit: For the record I don't advocate anyone use this. I would much rather revisit the design to avoid being painted in this particular corner in the first place. Please consider my answer as an academic solution to a theoretical problem, not an actual engineering recommendation.
Since virtual template methods in C++ arent allowed, you can make a class template and call static function of class template param.
#include <iostream>
#include <vector>
using std::cout;
using std::endl;
//*******************************************************************
//*******************************************************************
struct DerivedStuff1
{
static void eval() { cout << "evaluating DerivedStuff1" << endl; }
};
struct DerivedStuff2
{
static void eval() { cout << "evaluating DerivedStuff2" << endl; }
};
//*******************************************************************
//*******************************************************************
class BaseClass
{
public:
virtual void eval() const = 0;
};
template<typename StuffType>
class DerivedClass1 : public BaseClass
{
public:
virtual void eval() const
{
std::cout << "We are in DerivedClass1: ";
StuffType::eval();
}
};
template<typename StuffType>
class DerivedClass2 : public BaseClass
{
public:
virtual void eval() const
{
std::cout << "We are in DerivedClass2: ";
StuffType::eval();
}
};
int main()
{
BaseClass* c1 = new DerivedClass1<DerivedStuff1>;
c1->eval();
c1 = new DerivedClass1<DerivedStuff2>;
c1->eval();
BaseClass* c2 = new DerivedClass2<DerivedStuff1>;
c2->eval();
c2 = new DerivedClass2<DerivedStuff2>;
c2->eval();
// deletes
return 0;
}
Output
We are in DerivedClass1: evaluating DerivedStuff1
We are in DerivedClass1: evaluating DerivedStuff2
We are in DerivedClass2: evaluating DerivedStuff1
We are in DerivedClass2: evaluating DerivedStuff2
You cannot mix templates (compile time) and polymorphic (runtime). That's it.
So, a posible workaround is remove templates. For example, it could take a function pointer or just more polymorphism:
//*******************************************************************
//*******************************************************************
struct InterfaceStuff{
virtual void eval() = 0;
}
struct DerivedStuff1 : public InterfaceStuff
{
void eval() { cout << "evaluating DerivedStuff1" << endl; }
};
struct DerivedStuff2 : public InterfaceStuff
{
void eval() { cout << "evaluating DerivedStuff2" << endl; }
};
//*******************************************************************
//*******************************************************************
class BaseClass
{
public:
virtual void eval(InterfaceStuff* interface) const = 0;
};
class DerivedClass1 : public BaseClass
{
public:
virtual void eval(InterfaceStuff* interface) const
{
std::cout << "We are in DerivedClass1: ";
interface->eval();
}
};
class DerivedClass2 : public BaseClass
{
public:
virtual void eval(InterfaceStuff* interface) const
{
std::cout << "We are in DerivedClass2: ";
interface->eval();
}
};
Another posible workaround is remove polymorphism, just use more templates:
struct DerivedStuff1
{
static void eval() { cout << "evaluating DerivedStuff1" << endl; }
};
struct DerivedStuff2
{
static void eval() { cout << "evaluating DerivedStuff2" << endl; }
};
//*******************************************************************
//*******************************************************************
class BaseClass
{
public:
template<typename Eval,typename StuffType> void eval() const
{
Eval::eval();
StuffType::eval();
}
};
class DerivedClass1 : public BaseClass
{
};
class DerivedClass2 : public BaseClass
{
};
One way of another, you have to choose one.
The following code is a simplified version of a VisitorPattern I have implemented on my project.
#include <iostream>
class AVisitor {
public:
virtual void visit(class A *) = 0;
};
class ExtendedVisitor : public AVisitor {
public:
virtual void visit(class B *) = 0;
};
class A {
public:
virtual void accept(AVisitor *visitor) {
std::cout << "Call accept of A" << std::endl;
visitor->visit(this);
}
};
class B : public A {
public:
void accept(AVisitor *visitor) override {
std::cout << "Call accept of B" << std::endl;
B *just_this = this;
visitor->visit(just_this); //why this calls to visit(A*)
visitor->visit((B*) just_this); //useless casting
}
};
class ActualVisitor : public ExtendedVisitor {
public:
void visit(A *x) override {
std::cout << "Call visit on A*" << std::endl;
}
void visit(B *x) override {
std::cout << "Never called" << std::endl;
}
};
int main() {
ActualVisitor visitor;
A *a = new B();
a->accept(&visitor);
}
I don't understand why the accept method of class B calls to the visitor(A*) method instead of visitor(B*). The main function prints
Call accept of B
Call visit on A*
Call visit on A*
Instead, the following code behaves as I expected:
#include <iostream>
class AVisitor {
public:
virtual void visit(class A *) = 0;
virtual void visit(class B *) = 0;
};
class A {
public:
virtual void accept(AVisitor *visitor) {
std::cout << "Call accept of A" << std::endl;
visitor->visit(this);
}
};
class B : public A {
public:
void accept(AVisitor *visitor) override {
std::cout << "Call accept of B" << std::endl;
B *just_this = this;
visitor->visit(just_this); //now it works
visitor->visit((B*) just_this);
}
};
class ActualVisitor : public AVisitor {
public:
void visit(A *x) override {
std::cout << "Call visit on A*" << std::endl;
}
void visit(B *x) override {
std::cout << "Call visit on B*" << std::endl;
}
};
int main() {
ActualVisitor visitor;
A *a = new B();
a->accept(&visitor);
}
It now prints:
Call accept of B
Call visit on B*
Call visit on B*
The problem then seems to be the inheritance of the AVisitor class. I wonder why this happens and what is the proper way to design a VisitorPattern with "specialized" visitors (here ExtendedVisitor can also visit a B object)
Your B::accept has the following signature:
void accept(AVisitor *visitor) override;
So, let's check the interface of AVisitor. It has
virtual void visit(class A *) = 0;
and that is all it has (in your first version). It is true that ExtendedVisitor has
virtual void visit(class B *) = 0;
but that does not override the method in AVisitor. In fact, your second version can help you see why. Since
virtual void visit(class A *) = 0;
virtual void visit(class B *) = 0;
can reside together in the same class (they are overloads in your second version), then they are distinct methods in this respect.
You are implementing Visitor incorrectly. Here's the right way:
class AVisitor {
public:
virtual void visit(class A *) = 0;
virtual void visit(class B *) = 0;
// virtual void visit(class C *) = 0; etc
// a separate function for every class in your hierarchy
};
and then
class ActualVisitor : public Visitor ...
There's no need for ExtendedVisitor.
Yes AVisitor must know about every class in your hierarchy. This is the principal drawback of this pattern.
If we have diamond inheritance and use public virtual base classes, we can stop the first constructor from being called multiple times. Now, I'd like to do the same sort of thing for functions outside of the constructor. For example, the code:
#include <iostream>
struct A {
virtual void foo() {
std::cout << "A" << std::endl;
}
};
struct B : virtual public A {
virtual void foo() {
A::foo();
std::cout << "B" << std::endl;
}
};
struct C : virtual public A {
virtual void foo() {
A::foo();
std::cout << "C" << std::endl;
}
};
struct D : public B, public C{
virtual void foo() {
B::foo();
C::foo();
std::cout << "D" << std::endl;
}
};
int main() {
D d;
d.foo();
}
produces the result
A
B
A
C
D
I'd like to modify it so that it just produces
A
B
C
D
What sort of strategies or patterns accomplish this?
EDIT 1
I like Tony D's answer better than the following. Nonetheless, it's in theory possible to use constructors of another class in order to define the proper hierarchy of functions. Specifically
#include <iostream>
struct A;
struct B;
struct C;
struct D;
namespace foo {
struct A {
A(::A* self);
};
struct B : virtual public A {
B(::B* self);
};
struct C : virtual public A {
C(::C* self);
};
struct D : public B, public C{
D(::D* self);
};
}
struct A {
private:
friend class foo::A;
friend class foo::B;
friend class foo::C;
friend class foo::D;
int data;
public:
A() : data(0) {}
virtual void foo() {
(foo::A(this));
}
void printme() {
std::cout << data << std::endl;
}
};
struct B : virtual public A {
virtual void foo() {
(foo::B(this));
}
};
struct C : virtual public A {
virtual void foo() {
(foo::C(this));
}
};
struct D : public B, public C{
virtual void foo() {
(foo::D(this));
}
};
foo::A::A(::A* self) {
self->data+=1;
std::cout << "A" << std::endl;
}
foo::B::B(::B* self) : A(self) {
self->data+=2;
std::cout << "B" << std::endl;
}
foo::C::C(::C* self) : A(self) {
self->data+=4;
std::cout << "C" << std::endl;
}
foo::D::D(::D* self) : A(self), B(self), C(self) {
self->data+=8;
std::cout << "D" << std::endl;
}
int main() {
D d;
d.foo();
d.printme();
}
Basically, the classes inside of the namespace foo do the computation for the function named foo. This seems a little verbose, so perhaps there's a better way to do it.
EDIT 2
Thanks again to Tony D for clarifying the above example. Yes, essentially what the above does is create temporary variables that adhere to the virtual base designation. In this way, we can use the constructor in order to prevent redundant computations. The extra cruft was to try and show how to get access to access to private members that may have been buried in the base class. Thinking about it a little bit more, there's another way to do this, which may or may not be cleaner depending on the application. I'll leave it here for reference. As with the last example, the weakness is that we're essentially required to wire the the inheritance again, by hand.
#include <iostream>
struct A {
protected:
int data;
public:
A() : data(0) {}
struct foo{
foo(A & self) {
self.data+=1;
std::cout << "A" << std::endl;
}
};
void printme() {
std::cout << data << std::endl;
}
};
struct B : virtual public A {
struct foo : virtual public A::foo {
foo(B & self) : A::foo(self) {
self.data+=2;
std::cout << "B" << std::endl;
}
};
};
struct C : virtual public A {
struct foo : virtual public A::foo {
foo(C & self) : A::foo(self) {
self.data+=4;
std::cout << "C" << std::endl;
}
};
};
struct D : public B, public C{
struct foo : public B::foo, public C::foo {
foo(D & self) : A::foo(self) , B::foo(self), C::foo(self) {
self.data+=8;
std::cout << "D" << std::endl;
}
};
};
int main() {
D d;
(D::foo(d));
d.printme();
}
Essentially, the call (D::foo(d)) creates a temporary who's constructor does the actions we desire. We pass in the object d by hand in order to access to the memory. Since the classes foo are inside of the classes A..D, this gives us access to the protected members.
Just an implementation of polkadotcadaver's idea. Here, Limiter is designed to be a reusable mechanism for this, and the virtual base class should have a member of that type. The controlled base-class function uses bool Limiter::do_next() to ask whether it should run "as usual" or return immediately, while the derived classes calling the base-class function get a scope-guard object from the limiter that takes ownership if not already claimed, and releases any ownership it had on destruction.
#include <iostream>
class Limiter
{
public:
Limiter() : state_(Unlimited) { }
class Scope
{
public:
Scope(Limiter& l)
: p_(l.state_ == Unlimited ? &l : NULL)
{ if (p_) p_->state_ = Do_Next; }
~Scope() { if (p_) p_->state_ = Unlimited; }
private:
Limiter* p_;
};
Scope get() { return Scope(*this); }
bool do_next()
{
if (state_ == Do_Next) { state_ = Suspended; return true; }
return state_ != Suspended;
}
private:
enum State { Unlimited, Do_Next, Suspended } state_;
};
struct A {
Limiter limiter_;
virtual void foo() {
if (limiter_.do_next())
std::cout << "A" << std::endl;
}
};
struct B : virtual public A {
virtual void foo() {
Limiter::Scope ls = A::limiter_.get();
A::foo();
std::cout << "B" << std::endl;
}
};
struct C : virtual public A {
virtual void foo() {
Limiter::Scope ls = A::limiter_.get();
A::foo();
std::cout << "C" << std::endl;
}
};
struct D : public B, public C{
virtual void foo() {
Limiter::Scope ls = A::limiter_.get();
B::foo();
C::foo();
std::cout << "D" << std::endl;
}
};
int main() {
D d;
d.foo();
}
Discussion of technique edited into your question
Took me a while to work out what you were doing in your code ;-P - so for the sake of discussion I'll post what I boiled it down to:
#include <iostream>
namespace foo {
struct A {
A() { std::cout << "A\n"; }
};
struct B : virtual public A {
B() { std::cout << "B\n"; }
};
struct C : virtual public A {
C() { std::cout << "C\n"; }
};
struct D : public B, public C{
D() { std::cout << "D\n"; }
};
}
struct A { virtual void foo() { foo::A(); } };
struct B : virtual public A { void foo() { foo::B(); } };
struct C : virtual public A { void foo() { foo::C(); } };
struct D : public B, public C { void foo() { foo::D(); } };
int main() {
D d;
d.foo();
}
For others' sake - this works by having the A..D::foo() functions create temporary objects of types foo::A..D, the constructors for which honour the virtual base designation so foo::A::A() is only called once.
As a general solution, an issue with this is that you have to manually synchronise the foo:: structures, so there's redundancy and fragility. It's clever though!
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