I have two classes A and B, both defining method m(). Although the signatures of these methods are the same, they are two totally different methods with different meanings. In class C, I want to update both m(). Instead of writing a new m() in class C that fuses the two m() from A and B, I want to override them separately. See the following code:
class A { public: virtual void m() {cout << "MA" << endl;}};
class B { public: virtual void m() {cout << "MB" << endl;}};
class C : public A, public B {
public: virtual void m() update A {cout << "MA2" << endl;}};
public: virtual void m() update B {cout << "MB2" << endl;}};
}
void func(A* a) { a->m(); }
int main() {
C* c = new C();
c->B::m(); //print "MB2"
func(c); //print "MA2"
return 0;
}
I know that the update syntax is not supported in C++, but is there any workaround to simulate this in C++?
A nasty part of multiple inheritance is that indeed there is only one m in C that overrides both. You need a middle-man class to disambiguate the call in case of 2 or more classes that define m. Fortunately, you can use a template in order to automate the process:
template<class C>
class MiddleMan : public C {
void m() override final { m_impl(this); }
protected:
virtual void m_impl(MiddleMan*) = 0;
};
Now you just use this template and override the new functions it adds:
class C : public MiddleMan<A>, public MiddleMan<B> {
private:
void m_impl (MiddleMan<A>*) override {cout << "MA2" << endl;}
void m_impl (MiddleMan<B>*) override {cout << "MA2" << endl;}
};
The implementation of m in each middle man class will call the new virtual functions that are overloaded. You then define these overloads. I used MiddleMan* as the extra parameter which facilitates overloading, but any type which is cheap to pass by value and depends on the template parameter will do for disambiguation.
You just cannot do that, for the same reason in C you can't have two functions with the same name: the compiler would not know which one to call!
To get the same effect that you want, I'd change your code to look as follows:
class A { public: virtual void ma() {cout << "MA" << endl;}};
class B { public: virtual void mb() {cout << "MB" << endl;}};
class C : public A, public B {
public: virtual void ma() override {cout << "MA2" << endl;} // these are *extra*: };
public: virtual void mb() override {cout << "MB2" << endl;} // these are *extra*: };
}
void func(A* a) { a->ma(); } // the problem here with a->m() would be
// that the compiler would not know which m() function to call --
// you basically want two pointers *crammed* somehow in the same vfptr entry,
// and the compiler to *automagically* know which one to call,
// depending on... unspecified conditions!
int main() {
C* c = new C();
c->B::m(); //this will never print "MB2" in your code;
//it will always print "MB", no matter what you do!
c->mb(); //print "MB2"
func(c); //print "MA2"
return 0;
}
I know, this may not be the answer you're looking for, but then you have to describe your problem better. In my opinion, this is a valid solution to your problem, as it's currently described.
Related
I have 3 classes: A, B, C. B inherits from A, and C inherits from B (so C is grandchild of A).
Every object has function talk() that displays text, in A and B it's virtual.
Let have outside function call(A &a), that takes object A by reference, and calls function talk().
Sending object C to the function, it uses talk() from B instead of C, even that at B talk() is virtual.
Why it is so? How to make it call version from C?
#include <iostream>
using namespace std;
class A {
public:
virtual void talk() = 0;
virtual void say() = 0;
};
class B : public A {
public:
virtual void talk() // Why C does not overrides this?
{ cout << "hello\n"; }
};
class C : public B {
public:
void talk (int a) // It should override B.talk();
{ cout << "bye\n";}
virtual void say() { cout << "my name\n"; }
};
void call(A &a) {
a.talk(); // Why does it call virtual talk() from B rather than from C?
a.say(); // This was found so it knows about object C
}
int main() {
C c;
call(c);
system("PAUSE");
return 0;
}
I'd expect that call(A &a) takes the furthest inheritance version if every class between has virtual talk()
In your example, C.talk(int) doesn't override B.talk() because C.talk takes an int as a parameter, so it's an entirely different function.
You can add override after a function declaration to get the compiler to check if it actually overrides anything:
class C : public B {
public:
// Here, the compiler complains because there's no talk(int) method
// That it can override
void talk (int a) override;
{ cout << "bye\n";}
virtual void say() { cout << "my name\n"; }
};
class Base
{
public:
virtual void print() = 0;
};
class A : public Base
{
int mClassA;
public:
A() : mClassA(1) {}
void print() override { std::cout << "print A" << std::endl; }
void foo( A& arg ) { std::cout << mClassA << std::endl; }
};
class B : public Base
{
int mClassB;
public:
B() : mClassB(2) {}
void print() override { std::cout << "print B" << std::endl; }
void foo( B& arg ) { std::cout << mClassB << std::endl; }
};
So I got class structure similar to this. What approach should I take to call foo without dynamic_cast each time?
int main()
{
Base * obj1 = new A();
Base * obj2 = new A();
dynamic_cast<A*>(obj1)->foo(*dynamic_cast<A*>(obj2));
}
I could create foo method with base class argument but I want to be sure that I'm passing A or B obejct as an argument.
You could use templates to make sure that a particular parameter of one of the class' member functions has at least a particular type. See the following code illustrating this:
template <class P>
class Base
{
public:
Base(int nr) : mClass(nr) {}
virtual void print() = 0;
virtual void foo( P& arg ) { std::cout << mClass << std::endl; }
protected:
int mClass;
};
class A : public Base<A>
{
public:
A() : Base(1) {}
void print() override { std::cout << "print A" << std::endl; }
virtual void foo( A& arg ) override { Base::foo(arg); cout << "is A for sure" << endl; }
};
class B : public Base<B>
{
public:
B() : Base(2) {}
void print() override { std::cout << "print A" << std::endl; }
virtual void foo( B& arg ) override { Base::foo(arg); cout << "is B for sure" << endl; }
};
int main()
{
Base<A> * obj1 = new A();
A* obj2 = new A();
obj1->foo(*obj2);
Base<B> * objb1 = new B();
B* objb2 = new B();
objb1->foo(*objb2);
// objb1->foo(*obj2);
// Non-const lvalue reference to type 'B' cannot bind to a value of unrelated type 'A'
}
It sounds like you're wanting to do something like this:
class Base
{
public:
virtual void foo(Base&) = 0;
};
class A : public Base
{
public:
void foo(A&);
};
class B : public Base
{
public:
void foo(B&);
};
In object oriented design, this is known as covariance (specifically, a "covariant method argument type").
The problem is that this goes against principles of good object oriented design. The Liskov substitution principle says that, if you have a base class Base, then any instances of subclasses of Base need to be interchangeable - but you want some subclasses of Base to not work with other subclasses of Base. (This is an oversimplification, but there are plenty of discussions online with more detail.)
If you want to do this - if it's the best solution in your case, in spite of the general advice of the Liskov substitution principle - then you can implement the checks yourself.
void A::foo(Base& base_arg) {
// This will throw a runtime exception if the wrong type
A& arg = dynamic_cast<A&>(base_arg);
std::cout << mClassA << std::endl;
}
Note that you're sacrificing some compile-time type safety now - if you accidentally try to call A::foo with an instance of B, you won't know until the code runs and you get an exception. (That's the whole point of virtual functions / dynamic dispatch / polymorphism - the behavior is determined at runtime.)
Another approach would be to use templates, like #Stephen Lechner's solution. That gives up runtime polymorphism, but it keeps strong type safety and better follows conventional OO design.
The Wikipedia article on covariance has a lot more discussion, including further example code.
I give the following example to illustrate my question:
class Base
{
public:
virtual void do()=0;
}
class A: public Base
{
public:
void do();
};
class B: public Base
{
public:
void do();
}
class AB: public Base
{
public:
void do()
{
a_.do();
// if not succeed
{
b_.do();
}
}
private:
A a_;
B b_;
}
From the above codes, we can see that class A, B and AB come from the same Base class. class AB, however, needs to invoke both class A and class B. Here is my question: what's the potential problem with the class AB? Are there other alternatives?
One alternative might be:
class Base
{
public:
virtual void do()=0;
}
class A: public Base
{
public:
void do();
};
class B: public Base
{
public:
void do();
}
class AB: public A
{
public:
void do()
{
A::do();
// if not succeed
{
b_.do();
}
}
private:
B b_;
}
I have no idea what you really want to achieve. But if all of your classes should only have one copy of instance data from Base, you need a virtual Base class.
The problem from your first example with AB is, that you have three! times data of class Base. One from inherit Base, one as part of Member B which itself derives from Base and the same from Member A. Is that what you intend?
I give you the following snipped to see how you can work with exact ONE copy of Base in all of your class instances. Maybe that is what you want to get?
I add some data to Base to see how construction works while using virtual base classes. It is important that the base class constructor will not be called from the constructors of directly inherited classes! You need to call the constructor directly from the outermost constructor as shown in class AB constructor!
As a remark: Virtual Base classes should be used only if nothing else fits the design. Often the need of such a solutions shows a design problem. But as always in programming: If this fits exactly your needs, it is technically absolutely ok to do it.
class Base
{
private:
std::string text;
public:
Base( const std::string& str ): text(str) {}
virtual void Do() { std::cout << text << std::endl; }
};
class A: virtual public Base
{
public:
A():Base("Default from A") {}
void FuncA() { std::cout << "FuncA" << std::endl; }
void Do() { std::cout << "Via A" << std::endl; Base::Do();}
};
class B: virtual public Base
{
public:
B(): Base ("Default from B") {}
void FuncB() { std::cout << "FuncB" << std::endl; }
};
class AB: public A,B
{
public:
//Important to know that init of Base MUST be done from here and not from A nor B !!
AB( const std::string &s): Base(s) {}
void Do() { std::cout << "Via AB" << std::endl; Base::Do(); A::Do(); B::Do();}
};
int main()
{
A a;
a.Do();
std::cout << "####" << std::endl;
B b;
b.Do();
std::cout << "####" << std::endl;
AB ab("Hallo");
ab.Do();
std::cout << "####" << std::endl;
}
what's the potential problem with the class AB?
I don't know of any well known problem that would necessarily arise from your design. You should ask yourself "Why would there be a problem?".
Are there other alternatives?
There are many alternatives. For example, neither A nor B contain any state, so you could just as well stop using classes in favor of free functions and replace dynamic binding with a function pointer.
To be able to compare different alternatives, you should first decide what problem you are trying to solve.
You should inherit from A and B and not from Base, because A and B already do so.
I have a diamond design currently, and I saw a related question here
In that question, let me assume that class B and class C are virtual inherited from Class A, so in Class D, when we need to call virtual functions, we need to specify which one needed to call.
D::foo()
{
B::foo(); //specify foo() in B
}
For my diamond design, I have a lot of virtual functions to rewrite, in order to let these functions called by correct B or C father class functions.
It is not good, a lot of repeated work need to be done, when I have child class, do you have some better solutions, so that I can call foo() of B in class D but no rewrite for the example above.
Since C++11, you can do an aliasing:
class A
{
public:
virtual void foo() { cout << "A" << endl; }
}
class B : public virtual A
{
public:
void foo() { cout << "B" << endl; }
}
class C : public virtual A
{
public:
void foo() { cout << "C" << endl; }
}
class D : public B, C
{
using B::foo;
}
This way, doin:
D obj;
obj.foo();
Will output B;
I think template classes might do the trick here.
http://www.cplusplus.com/doc/tutorial/templates/
I have a problem that I have not yet tested/compiled and wondering if it is possible and if it is bad design?
My Problem:
I want to have an abstract base class A and a abstract derived class B.
I realize if this is possible I will have a number of pure virtual member functions in each class and also I will not be able to initialize these objects, but that is a given for abstract classes.
In my design I will have another derived class C which I would then initialize - class C would be derived from class B.
I would have something that looked like this
class C
^
|
abstract class B
^
|
abstract base class A
My Question:
Is this possible first of all? I would suspect so, but not declaring the pure virtual functions in A in class B may be troublesome?
e.x.
class A {
public:
virtual void test()=0;
};
class B: public A {
public:
virtual void test()=0;
virtual void anotherTest()=0;
};
Is the above okay?
Is this bad c++ design? In future I will have derived classes from A so it would be nice to have this design.
Nothing wrong with it, and it will certainly work. Example follows
stefanos-imac:dftb borini$ more test.cpp
#include <iostream>
class A {
public:
A(void) { std::cout << "A" << std::endl; }
virtual void method1() = 0;
};
class B : public A {
public:
B(void) : A() { std::cout << "B" << std::endl; }
virtual void method2() = 0;
};
class C : public B {
public:
C(void) : B() { std::cout << "C" << std::endl; }
virtual void method1() { std::cout << "method1" << std::endl; }
virtual void method2() {std::cout << "method2" << std::endl; }
};
int main() {
C c;
c.method1();
c.method2();
}
stefanos-imac:dftb borini$ ./a.out
A
B
C
method1
method2
Thank you for reminding me that I can still type basic C++.