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.
Related
This is purely a theoretical question. I don't have a particular use case in mind.
Can the virtuality of a C++ function be suppressed somewhere down the class hierarchy, or is it that once a virtual function is defined in a base class, it remains virtual down the rest of its class hierarchy?
I wrote some sample code where I was attempting to suppress the virtuality of a method defined up the class hierarchy but I did not succeed. My sample code follows:
class Base {
public:
virtual void myFunc() {
std::cout << "myFunc in Base" << std::endl;
}
};
class Child : public Base {
public:
void myFunc() {
std::cout << "myFunc in Child" << std::endl;
}
};
class GrandChild : public Child {
public:
void myFunc() {
std::cout << "myFunc in GrandChild" << std::endl;
}
};
int main() {
Base* ptr = new GrandChild();
ptr->myFunc();
return 0;
}
The output is as follows:
myFunc in GrandChild
One thing you can do is create a member with a different signature (even using defaulted arguments).
That is:
struct Base
{
virtual void foo()
{
std::cout << "Base::foo" << std::endl;
}
};
struct Derived : Base
{
void foo(int = 0)
{
std::cout << "Derived::foo" << std::endl;
}
};
...
Base * ptr = new Derived;
ptr->foo(); // will invoke Base::foo()
#include <iostream>
class A {
protected:
int foo;
};
class B : public A {
public:
B(int bar) { foo = bar; }
int method() { return foo; }
};
class C {
private:
A baz;
public:
C(A faz) { baz = faz; }
A get() { return baz; }
};
int main(void) {
C boo(B(1));
std::cout << boo.get().method() << std::endl;
return 0;
}
I have a base class A which B is a derived class of. Class C takes an A yet I have passed a derived class (B) in its place. No warnings or errors passing a B to C, but I'd like to have method visibility of method() in the above situation.
I'm not very familiar with virtual but I did try to add virtual int method() = 0; to A which lead to further errors.
Consider were I to add a second derived class:
class D : public A {
public:
D(int bar) { foo = bar; }
int method() { return foo+1; }
};
I'd like C to be able to take either B or D and my best assumption would be to take an A and let it handle it.
How do I use polymorphism correctly in this fashion?
Expected output with the below:
int main(void) {
C boo(B(1));
C boz(D(2));
std::cout << boo.get().method() << std::endl;
std::cout << boz.get().method() << std::endl;
return 0;
}
Would be:
1
3
First of all, in order to use A polymorphically, you need to add a virtual destructor, otherwise you will run into undefined behavior when trying to destroy the object. Then the method that you want to call through A must be virtual as well. If it shouldn't have an implementation in the base class itself, make it pure virtual:
class A {
protected:
int foo;
public:
virtual ~A() {}
virtual int method() = 0;
};
Then in C you need to use pointers or references to A, since polymorphism only works with those.
If you want C to own the A, as your code example to suggest, then you need to provide a destructor deleting the pointer and you need to disable copying of the class (or decide on some useful semantics for it):
class C {
private:
C(const C&); // Don't allow copying
C& operator=(const C&); // Don't allow copying
A* baz;
public:
C(A* faz) : baz(faz) { }
~C() { delete baz; }
A& get() { return *baz; }
};
int main(void) {
C boo(new B(1));
C boz(new D(2));
std::cout << boo.get().method() << std::endl;
std::cout << boz.get().method() << std::endl;
return 0;
}
Ideally you would upgrade to C++11 and use std::unique_ptr<A> instead of A* as member. But even if you can't do that, consider using boost::scoped_ptr<A>, which will manage the deletion for you (you don't need the destructor) and will make the class non-copyable by default. It also provides better exception-safety to encapsulate allocations in smart pointers like that.
If you need to call method() of type B using base class type A there has to be lookup during the runtime. The lookup is necessary to answer the question: Which method should be called? - the one that corresponds the type in a current line? Or other method in inheritance hierarchy?" If you expect method() from class B to be called when you have pointer or reference to A then you have to create a lookup table. This table is called vtable (from virtual functions table) and it's defined by adding virtual keyword to functions.
#include <iostream>
class A {
public:
virtual ~A(){}
virtual int method() = 0;
protected:
int foo;
};
class B : public A {
public:
B(int bar) { foo = bar; }
int method() {
std::cout << "Calling method() from B" << std::endl;
return foo; }
};
class C {
private:
A* baz;
public:
C(A* faz) { baz = faz; }
A* get() { return baz; }
};
int main(void) {
A* element = new B(1);
C boo(element);
boo.get()->method();
return 0;
}
It prints "Calling method() from B". Please keep in mind that the code is for presentation purposes and it's not good from best practices perspective.
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.
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 these two classes:
class A {
public:
A() { m_ptr = NULL; }
void (*m_ptr)();
void a() { if (m_ptr) m_ptr(); }
};
class B : public A {
public:
B() { m_ptr = b; }
void b() {
std::cout << "B::b() is called" << std::endl;
}
};
And I want to use them like this:
B b;
b.a();
and get the following to be called B::b().
Of course this is not being compiled as B::b is not of type void(*)().
How can I make it work?
UPDATE. To whom who asks "why?" and "what for?".
The class A is a very basic class which has many successors in production code. The class B is 6-th successor and I want to extend A (the most convinient place) to call there one more method (from B) which can be present and may be not in another successors af A and B.
A virtual method with empty body can be employed for that but it is ugly and I want to avoid it. Abstract method even more so (because of existing derived successors code).
I don't want to use external function of type void (*)() to not loose access to internal data of all hierarchy.
You can't make it work as your classes are defined now.
Calling a non-static member function of another class requires an instance of that class. You either need to store a reference to the object that owns the member function when storing the function pointer, or pass a reference to the object when you make the call to A::a.
You also need to declare m_ptr with the type void (B::*)(), which is pointer to member of B that is a function taking no parameters and returning void.
Look at this example:
class A {
public:
A() { m_ptr = nullptr; }
void a(B& b) { if (m_ptr) (b.*m_ptr)(); } // Now takes reference to B object.
void (B::*m_ptr)(); // Pointer to member function of B.
};
class B : public A {
public:
B() { m_ptr = &B::b; } // Adress of qualified function.
void b() {
std::cout << "B::b() is called" << std::endl;
}
};
Now we can call B::b like this:
B b;
b.a(b); // Pass reference to b when calling.
Your use of inheritence in this way is confusing as it implies that the real problem you are trying to solve is to invoka a member of a derived class through the base class. This is usually accomplished using a simple virtual function like this:
class A {
public:
virtual ~A() {}
void a() const { b(); } // Call b.
private:
virtual void b() const {}
};
class B : public A {
public:
virtual void b() const override { // C++11 override specifier (optional).
std::cout << "B::b() is called" << std::endl;
}
};
And used like this:
B b;
b.a(); // B::b is called.
Well, probably not the purpose of this exercise, but you can simply declare static void b() if you want to make it work.
Another option is to declare friend void b(), but then the "B::b() is called" printout would be stating a wrong fact.
I would suggest using CRTP since you want to avoid virtual mechanism. Note, however, your code might require some design changes to accommodate this pattern. But it does provide type safety and has no run-time overhead. Hope it helps.
Code on ideone.com:
#include <iostream>
#include <type_traits>
namespace so {
class B;
template<typename T>
class A {
public:
template<typename U = T, typename = typename std::enable_if<std::is_same<U, B>::value>::type>
void foo_A() {
std::cout << "foo_A : ";
static_cast<U *>(this)->foo_B();
}
};
class B: public A<B> {
public:
void foo_B() {
std::cout << "foo_B" << std::endl;
}
};
class C: public A<C> {
public:
void foo_C() {
std::cout << "foo_C" << std::endl;
}
};
} // namespace so
int main() {
so::B b_;
so::C c_;
b_.foo_A();
b_.foo_B();
//c_.foo_A(); Compile error: A<C>::foo_A() does not exist!
c_.foo_C();
return (0);
}
Program output:
foo_A : foo_B
foo_B
foo_C