i have something like this
class A {
virtual void doBla(A *a) = 0;
};
class B : public A {
virtual void doBla(B *b) { // do stuff ;};
};
and i want to do something like
A* a = new B();
B* b = new B();
a->doBla(b);
or: all children of A are supposed to have a method doBla which takes a parameter of the type of the child. Hope you get my problem and hope someone can help me or convince me that this is bad style :)
edit: added virtual to the methods
You cannot overload functions across base/child classes, and doBla member function of class A must be public if you want to call it from outside:
class A {
public:
virtual void doBla(A *a) = 0;
};
class B : public A {
virtual void doBla(A *a) { /*do stuff*/ }
};
Edit: Note that the declaration of doBla function is similar in A and B classes.
This is impossible as it stands - a doesn't have a doBla(B* b) function, so when you try to call it on the a instance the compiler can't guarantee in any way that function actually exists, and it doesn't know how to look it up. That's an error or ten.
What you might be looking for is double dispatch.
class A {
public:
virtual void doBla(A* a) { a->doBla_impl(this); }
private:
virtual void doBla_impl(A* a);
virtual void doBla_impl(B* b);
// etc
};
class B : public A {
public:
virtual void doBla(A* a) { a->doBla_impl(this); }
private:
virtual void doBla_impl(A* a);
virtual void doBla_impl(B* b);
// etc
};
The trouble with this is that you have to know all the derived types in the base class, which is not always possible or feasible.
Related
Can I somehow create a new subclass method in C++ with the same name as a virtual one in base class, but stopping inheritance?
Let me explain it with some more details, consider this code:
#define L(m) std::cout << m << std::endl;
class A {
public:
virtual void func() { L("A::func"); };
virtual void func2() { L("A::func2"); };
};
class B: public A {
public:
void func() { L("B::func"); }; //implements A::func
void func2(){ L("B::func2"); }; //implements A::func2
};
class C: public A {
public:
void func2() { L("C::func2"); }; //implements A::func2
void func() { L("C::func"); }; //meant to declare a new function but accidentally overrides A::func
};
I don't want to declare func as final in A (I know it would stop inheritance, but I need that for class B).
Also I want to call C::func2 with A:
C c;
A* a = &c;
a->func2(); //must use C::func2 (standard inheritance)
a->func(); //must use A::func !!! (possible?)
c.func2(); //must use C::func2
c.func(); //must use C::func
Obviously I can rename C's func to something else but anyway, is this somehow achievable without completely abusing C++ norms?
Try this :
class C: public A {
public:
void func2() { L("C::func2"); };
void func(int i = 0) { L("C::func"); };
};
The C::func is hiding the A::func one with a different signature. I got this result :
C::func2
A::func
C::func2
C::func
Instead of this with your code :
C::func2
C::func
C::func2
C::func
A question about inheritance and function overriding.
// base.h
class Base {
protected:
void a();
public:
void b();
}
// base.cc
void Base::a() {
// Empty.
return;
}
void Base::b() {
this->a();
}
// derived.h
class Derived : public Base {
protected:
void a();
}
// derived.cc
void Derived::a() {std::cout << "OK" << std::endl;}
So in my program it's Derived* p = new Derived(), but p->b() doesn't print OK? Sorry for the newbie question.
You must declare a function virtual in order to make inheritance work.
// base.h
class Base {
protected:
void a();
public:
virtual void b();
}
You need to to mark b() virtual in the base class declaration:
class Base {
protected:
void a();
public:
virtual void b();
};
And note the semicolon at the end of the class declaration: this is required in C++. Note that you don't need to write virtual in the derived classes, although some folk adopt that style.
(Polymorphism is not automatic in C++, unlike Java).
I have an example code snippet:
class A
{
public:
virtual void func1();
virtual void func2();
};
class B
{
public:
virtual void func2();
virtual void func3();
};
void main()
{
A *obj = new B;
obj->func3();
}
Why does the line obj->func3(); return error?
(we know that a separate virtual table is created for each class)"
Because obj is a pointer to A. A doesn't have func3 on it, so you can't call it.
Note: I've assumed you actually wanted to inherit B from A - it would error before the call, on the assignment in current state.
There's no way this could possibly work. Consider:
Class B : public A
{
void Foo (int);
};
class C : public A
{
void Foo (char);
};
class D : public A
{
void Foo (double);
}
void bar (A* obj)
{
obj->Foo (1); // Uh oh!
}
How can the compiler know what code to generate? Should this pass an integer? A float? A character?
And it's never safe, because the compiler is not able to see the definitions of all the derived classes when it's compiling functions like bar.
If you want to call a function through pointers to a base class, the base class needs to at least define what parameters that function takes.
Your code should look like this if it needs to work. You need to declare the function in base class otherwise in vtable for func3() it space will not be alloted in base class.
class A
{
public:
virtual void func1();
virtual void func2();
virtual void func3(); //virtual function , linking at run time depends on what object it points to
};
class B : public A //public inheritance
{
public:
virtual void func2();
virtual void func3();
};
void main()
{
A *obj = new B; //base class pointer pointing to derived class object
obj->func3(); //since func3() is declared as virtual , dynamic linking takes place and since at
// run times it points to object b , function in class B is invoked
}
I have a linked list of Foo objects. Foo is a base class, which has several classes inherit from it. Say, classes A, B, and C.
I am cycling through this linked list and calling a method some_method, which has 3 definitions; one for each child class:
some_method(A a);
some_method(B b);
some_method(C c);
The linked list is generic, so it is of type Foo, as it has an assortment of A, B and C objects.
When I'm cycling through the linked list at current_element, calling some_method(current_element);, how can I make it call the right method? The compiler complained until I wrote a some_method that took the generic Foo, and it only calls into that method.
Depending on your requirements, you may want to consider using polymorphism. To do this, add a pure virtual method to your base node class, and move the corresponding methods to the derived classes.
class Foo
{
public:
virtual void some_method() = 0;
};
class A : Foo
{
public
virtual void some_method()
{
// move the body of some_method(A a) here
}
};
For this to work, your linked list will need Foo*, instead of Foo.
class Node
{
public:
Foo* foo;
Node* next;
};
// ...
Node* someNode = GetNode();
// Calls correct method - A::some_method, B::some_method, or C::some_method
someNode->foo->some_method();
If you can't put some_method in Foo/A/B/C, then you might want to look into the Visitor design pattern:
http://en.wikipedia.org/wiki/Visitor_pattern
This is the "double dispatch" problem. You can use the visitor pattern. Usually the Visitor is a base class so you can re-use this design for multiple problems.
#include <iostream>
class FooVisitor;
class Foo
{
public:
virtual void some_method() = 0;
virtual void visit(FooVisitor* v) = 0;
};
class A;
class B;
class FooVisitor
{
public:
virtual void visit(A* a){ std::cout << "A" << std::endl;}
virtual void visit(B* b){std::cout << "B" << std::endl;}
};
class A : public Foo
{
public:
virtual void some_method()
{
// move the body of some_method(A a) here
}
virtual void visit(FooVisitor* v) { v->visit(this);}
};
class B : public Foo
{
public:
virtual void some_method()
{
// move the body of some_method(A a) here
}
virtual void visit(FooVisitor* v) { v->visit(this);}
};
int main()
{
FooVisitor fv;
Foo* f1 = new A;
f1->visit(&fv);
Foo* f2 = new B;
f2->visit(&fv);
getchar();
}
Two ways:
1) the better way:
Reverse your design such that someMethod is a virtual method of the base class Foo and redefine it in the derived classes. As:
class Foo {
public:
virtual void someMethod() = 0;
};
class A {
public:
void someMethod() { /* implementation specific to A here */ };
};
class B {
public:
void someMethod() { /* implementation specific to B here */ };
};
class C {
public:
void someMethod() { /* implementation specific to C here */ };
};
Then calling the someMethod on a pointer to Foo will automatically call the method from the appropriate class. If that cannot be done because someMethod cannot be implemented as part of Foo or its derivatives (e.g. it needs access to private members of the class it is currently in in your design), then you might try to split this functionality apart into subproblems that can be put into virtual methods of these classes A B C.
2) the "I don't have a choice" way:
Use RTTI (Run-Time Type Identification), it is included in C++. It requires that your base class Foo has at least one virtual method. You need to #include <typeinfo>, then use typeid() on the pointer, it will return a type_info object, and you can compare its name() result with the class names A B and C. This isn't a very nice approach because it has more overhead and it breaks OOP design principles. But if that's the only option, it's fine.
RTTI is your friend here. The example given in the link will guide you further
You can call the method for the child class as a member method. For exampleA a = new A(); a.some_method() should call the correct the method. Within some_method() you can reference to object using keyword this.
Will a function pointer to a class member function which is declared virtual be valid?
class A {
public:
virtual void function(int param){ ... };
}
class B : public A {
virtual void function(int param){ ... };
}
//impl :
B b;
A* a = (A*)&b;
typedef void (A::*FP)(int param);
FP funcPtr = &A::function;
(a->*(funcPtr))(1234);
Will B::function be called?
Yes. Valid code to test on codepad or ideone :
class A {
public:
virtual void function(int param){
printf("A:function\n");
};
};
class B : public A {
public:
virtual void function(int param){
printf("B:function\n");
};
};
typedef void (A::*FP)(int param);
int main(void)
{
//impl :
B b;
A* a = (A*)&b;
FP funcPtr = &A::function;
(a->*(funcPtr))(1234);
}
Yes. It also works with virtual inheritance.
The function will be called, as you just try to invoke inherited function.
The best test for that thing is to make the methods in the class A a pure virtual method. In both cases (with or without pure virtual methods), B::function will be called.