For example, I have an abstract base class A and B. A has a virtual method as follows
class A
{
public:
virutal void f(B& b) = 0;
};
For class A1
class A1 : public A
{
public:
void f(B& b) override { b.f(A1); }
};
And thus for B, it needs a virtual method f(A1)
class B
{
public:
virtual void f(A1& a) = 0;
};
And in class B1 : public B, the virtual method is implemented. The problem is that when another class A2 : public A is added, I have to add a virtual method virtual void f(A2& a) = 0 in class B, which I think it breaks the code because I don't know if A2 even A1 is added or not when I design class B. How to avoid it but implement the equivalent requirements? Any C++ feature can be used even with templates.
Unfortunately, there's no such thing as a virtual template function in C++ (this is what I believe you're trying to accomplish, after parsing your question).
The closest, and the least ugly solution I can think of, is to have the virtual function in base class B take the base class A as a parameter:
class B
{
public:
virtual void f(A& a) = 0;
};
B1 overrides that, and then uses dynamic_cast to cast its parameter to an instance of A1.
In this manner, you can continue an define each Ax and Bx pair of derived classes, without having to change the API interface in the base class, between the two hierarchies.
A bit ugly, but the question states "any C++ feature can be used", and dynamic_cast certainly qualifies under that requirement.
Related
I have the following classes :
class A { };
class B {
public:
B(){}
virtual ~B(){};
};
class B1 : public B{
public:
B1(){}
virtual ~B1(){};
};
class B2 : public B{
public:
B2(){}
virtual ~B2(){};
};
class C1 : public A, public B1{
public:
C1(){}
virtual ~C1(){};
};
class C2 : public A, public B2{
public:
C2(){}
virtual ~C2(){};
};
I want to know if an object of type B is also of type A :
B*b = new C1(); // or new B, or new C2 ...
if(dynamic_cast<A*>(b))
{
...
Is my dynamic_cast the correct way do that (it compiles and it runs)?
Thank you.
To be able to use dynamic_cast all parents of the object needs to be polymorphic. I.e. you need to add at least one virtual function to the A class (like the destructor).
Once you fix that then your dynamic_cast is fine.
Class A is different than Class B in the C++ type system. Since they are both empty, they should be same however they are instatiated in memory. Even empty classes have the identity property.
dynamic_cast<new_type> (expression) commonly is used as: dynamic_cast<derived_type> (myBase). In this case "If expression is a pointer or reference to a polymorphic type Base, and new_type is a pointer or reference to the type Derived a run-time check is performed:" see cppreference.com search for dynamic_cast. This allows you to cast the base class back down to the derived class. The programmer must know that the derived class exists.
I stumbled upon the following problem: I have two packages A and B working fine for each own. Each has its own interface and his own implementation. Now i made a package C combining a adapter of A with a concrete Implemenation of B. C actually only implements the Interface of A and is only inheritating and using the Interface of B internally for now. Most of the times that was enough to have only access to the Interface A from a Container, but now i need the methods from B accessible too. Here is the simple example:
//----Package A----
class IA
{virtual void foo() = 0;};
// I cant add simply bar() here, it would make totally no sense here...
class A : public IA
{virtual void foo() {doBasicWork();} };
//----Package B----
class IB
{virtual void bar() = 0;};
class B1 : public IB
{
//Some special implementation
virtual void bar() {}
};
class B2 : public IB
{
//Some special implementation
virtual void bar() {}
};
// + several additional B classes , with each a different implementation of bar()
//---- Mixed Classes
class AB1 : public B1, public A
{
void foo() {A::foo(); B1::bar();}
};
class AB2 : public B2, public A
{
void foo() {A::foo(); B2::bar();}
};
// One Container to rule them all:
std::vector<IA*> aVec;
AB1 obj1;
AB2 obj2;
int main(){
iAvector.push_back(&obj1);
iAvector.push_back(&obj2);
for (std::vector<IA>::iterator it = aVec.begin(); it != aVec.end(); it++)
{
it->for(); // That one is okay, works fine so far, but i want also :
// it->bar(); // This one is not accessible because the interface IA
// doesnt know it.
}
return 0;
}
/* I thought about this solution: to inherit from IAB instead of A for the mixed
classes, but it doesnt compile,
stating "the following virtual functions are pure within AB1: virtual void IB::bar()"
which is inherited through B1 though, and i cant figure out where to add the virtual
inheritence. Example:
class IAB : public A, public IB
{
// virtual void foo () = 0; // I actually dont need them to be declared here again,
// virtual void bar () = 0; // do i?
};
class AB1 : public B1, public IAB
{
void foo() {A::foo(); B1::bar();}
};
*/
The question is, how to achieve a combination of both Packages A and B, so that both Interfaces are accessible from one Container, while all the implementation details from A and B still get inherited?
The obvious solution is to create a combined interface:
class IAB : public virtual IA, public virtual IB
{
};
, have your AB1 and AB2 derive from it (in addition to their
current derivations), and keep IAB* in the vector.
This means that B1 and B2 must also derive virtually from
IB; given the direction things seem to be going, A should
probably also derive virtually from IA.
There are strong arguments that inheritance of an interface
should always be virtual. Without going that far: if a class is
designed to be derived from, and it has bases, those bases
should be virtual (and arguably, if a class is not designed to
be derived from, you shouldn't derive from it). In your case,
you're using the classic mixin technique, and generally, the
simplest solution is for all inheritance in a mixin to be
virtual.
Say we have a class inheriting from two base classes (multiple inheritance). Base class A is abstract, declaring a pure virtual function foo, the other base class B declares and implements a function foo of the very same signature.
struct A
{
virtual void foo(int i) = 0;
};
struct B
{
virtual void foo(int i) {}
};
struct C : public A, public B {};
I want to use the implementation of foo from base class B in my derived class C. However, if I do not implement the function foo a second time in my derived class C, I cannot instantiate any object of it (it remains abstract). Virtual inheritance does not help here as expected (class A and class B have no common base class).
I wonder if there is a way to "import" the implementation of foo from class B into class C in order not to have to repeat the same code.
Above example is of course contrived. The reason I want implement foo in class B is that I want to derive class D : public B and use class Bs implementation of foo. I know that inheritance is not (primarily) intended for code reuse, but I'd still like to use it in that way.
In java, your sample code works. In C++ it doesn't. A subtle difference between those languages.
Your best option in C++ is to define C::foo() by forwarding to B::foo():
struct C : public A, public B
{
virtual void foo(int i) { B::foo(i); }
};
Suppose I have this class hierarchy:
class A {
public:
virtual void foo(Base *b) = 0;
};
class B {
public:
virtual void bar() = 0;
};
class C : public A, public B {
public:
virtual void viz() = 0;
};
class E : public C {
public:
/** Some non-pure virtual functions, does not implement foo */
};
class F : public E {
/** does not implement foo */
}
class G : public E {
/** does not implement foo */
}
Now, I would like to define derived, "templatized" versions of F and G, which declares a method foo(T *s) and where the implementation of foo(Base *s) simply calls foo(T *s) by applying a static_cast.
Moreover, I don't wan to expose the template arguments to A, because users of these interfaces (A, B, C, E) should not be exposed to the template parameters (I'm writing a plugin architecture and user-types that derives a given interface are passed back and forth from plugins to base system).
What I thought was to define this class:
template <typename T>
class GA : public A{
...
}
and to define the "templatized" derivations of F and G like this:
template <typename T>
class GF : public F, public GA {
...
}
the problem is that GF sees two different declarations of foo() (one given by A, the other by GA), so the compiler throws me an error when I try to instantiate GF because foo(Base) is not defined.
How can I solve this?
Why do you need multiple inheritance? Why not just class C : public Impl { ... }?
I think the problem is that Impl inherits class A and class C inherits both Impl and A. This means there will be two instances of class A where first A's foo is implemented by Impl and a seconds one is still pure virtual. Virtual inheritance can solve this problem, for example:
class A {
public:
virtual void foo () = 0;
};
class Impl : virtual public A {
public:
virtual void foo () {}
};
class C
: virtual public A
, public Impl
{
};
I would suggest something different. Declare the function as a pure virtual function, and then just trivially implement it in the derived classes by forwarding the call:
class A {
public:
virtual void foo() = 0;
};
void A::foo() {}
class B : public A {
void foo() { A::foo(); }
};
But that does not mean that you cannot achieve what you are trying to do. If you want to implement that operation in another class and use inheritance, you can do it in two different ways:
Intermediate type:
Implement an intermediate type that provides the functionality, then each derived type can extend either the original A or the intermediate I type:
class I : public A {
public:
void foo() {}
};
class B : public I {}; // inherits the implementation
class C : public A { // needs to provide it's own implementation
void foo() {}
};
Virtual inheritance:
Alternatively you can use virtual inheritance (of the three options I would avoid this). In this way you can create a hierarchy where V inherits virtually from A and provides the implementation. The rest of the classes can either inherit from A directly or inherit from A virtually and also inherit from V. By using virtual inheritance you ensure that there is a single A subobject in your hierarchy:
class V : public virtual A {
public:
void foo() {}
};
class B : public virtual A, V { // Inheritance from V is a detail, can be private
// no need to provide foo
};
Note that this approach is overkill for this particular limited problem, and that it has side effects (the layout of the objects will be different and they will be slightly bigger in size). Again, unless you want to mix and match functions from different sibling classes, I would avoid this.
What was wrong in your code
The problem in your code is that you are inheriting from A multiple times, one through D and another directly. While in the path from D the virtual function is no longer pure, in the direct path from A the virtual function is still undefined.
That also causes the second issue in the error message: ambiguity. Because there are two A subobjects, when you try to call foo on the most derived type, the compiler cannot figure out on which of the two A subobjects you want to execute the request. The same type of ambiguity problems would arise if you tried to cast from the most derived type into A directly, as the compiler would not know to which A you want to refer.
Impl does not implement A's method in D and C, it's a completely different base.
You should derive Impl from A, then derive every class of that subset from Impl instead of A.
If you want to inherit from both the A and Impl, then you need to use virtual inheritance.
Edit:
See #Vlad's answer for more details.
Hello :) i would like to ask, if it's posible to make something like this:
i have base class (parent) A and three other classes (childs) B C D
in class A, i have virtual functions, that's ok.
but what if i need a virtual class ?
class A
{
public:
virtual int func1()=0;
virtual int func2()=0;
virtual class AB; // !!!!???
};
class B
{
public:
int func1();
int func2();
class AB
{
public:
....
};
};
classes B C D are same as class B. Now, i would like to create class instance and it should automaticly "redirect" class to instance of B or C D etc like functions.
is it possible ? i hope, you understand :) Thank you very much for answer.
This is fundamentally impossible. A virtual function call is determined at runtime. A class changes the behaviour of the program at compile-time. You can't make a compile-time determination at runtime unless runtime and compiletime are the same time, i.e. using a JIT or other dynamic code generators. In standard C++, this is impossible.
What you CAN do is have a base class AB, with a virtual function that creates a class that is guaranteed to inherit from this base class, and then return a pointer to that.