I have a class C that inherits both from Ai and B. A and B are unrelated. This is all best explained with the code below. In main(), I have a variable a defined as std::unique_ptr<A>, but initialized with C. I cannot change this definition.
My question is, given a defined like this, how can I call functions defined in B or C or Ai correctly?
#include <memory>
class A
{
public:
void fun_a() {}
};
class B
{
public:
void fun_b() {}
};
class Ai : public A
{
public:
void fun_ai() {}
};
class C: public Ai, public B
{
public:
void fun_c() {}
};
int main()
{
// I cannot change the following definition:
std::unique_ptr<A> a = std::make_unique<C>();
a->fun_a();
//a->fun_b(); // How ?
//a->fun_c(); // How ?
//a->fun_ai(); // How ?
return 0;
}
You can static_cast to C*:
static_cast<C*>(a.get())->fun_b();
static_cast<C*>(a.get())->fun_c();
static_cast<C*>(a.get())->fun_ai();
or you could make it polymorphic:
class A {
public:
virtual ~A() = default;
void fun_a() { std::cout << "fun_a\n"; }
};
and then dynamic_cast:
dynamic_cast<B*>(a.get())->fun_b();
dynamic_cast<C*>(a.get())->fun_c();
dynamic_cast<Ai*>(a.get())->fun_ai();
Note: dynamic_casts to pointer types may fail and return nullptr so, if there's any doubt, check the return value.
Demo
Related
I'm working on a small project, and I found myself in a situation like this :
class A{}
class B : class A {
public:
void f();
int getType() const;
private:
int type;
}
class C : class A{
public:
int getType() const;
private:
int type;
}
I want to know if there's a way to call the f() function (in class B) from an object of type A?
I tried this but it says function f() cannot be found in class A :
int main(){
vector<A*> v;
// v initialized with values of A ...
if (v->getType() == 1){ // 1 is the type of B
v->f();
}
}
As you've seen, this code won't compile because A doesn't have an f method. In order to make it work, you'd have to explicitly downcast the pointer:
B* tmp = dynamic_cast<B*>(v);
tmp->f();
To begin with, with your current classes, you can't call getType() on an A*. Because the interface of A doesn't have this method. To solve this problem, you either need to make getType a virtual function in A, or move the type field to base class A (as protected) and initialize it in the constructors of the child classes. Let me show you the first method, because I think it is a better approach, since it makes the objective of this function more clear.
class A {
public:
virtual int getType() { return 0; } // or delete the function: ... getType() = 0;
}
class B : public A {
public:
int getType() override { return 1; }
}
With these classes, once you create an instance of B, getType() returns 1 when called on that instance, whether it is pointed to by an A* or B*:
A *object = new B();
object->getType(); // returns 1
Now, if you need to access the f() from B, you can again add it as a virtual method to A's interface, or make a cast to B*.
Using a virtual method:
class A {
public:
virtual void f() { /* a default action maybe? */ }
}
class B : public A {
public:
void f() /* override if you want */ { /* whatever this function does in B */ }
}
...
for (A *ptr : v)
ptr->f();
Using a cast:
class A {
public:
virtual int getType() { return 0; }
}
class B : public A {
public:
void f();
int getType() override { return 1; }
}
...
for (A *ptr : v)
if (ptr->getType() == 1)
dynamic_cast<B*>(ptr)->f();
I want a class that can only be instantiated as a member of another class.
Id est:
class A
{
public:
A() :
member_()
{};
void letBSayHi() { member_.sayHi(); }
private:
B member_;
};
class B
{
public:
void sayHi() { printf("hola!"); }
};
thus:
A alpha; // valid
alpha.letBSayHi(); // # hola!
B beta; // invalid
beta.sayHi(); // impossible
The singleton pattern obviously wouldn't work, as I want one instance of class B for every instance of class A. But any instantiation of class B other than as a class A-member should be prohibited.
Make B a private nested class of A:
class A {
public:
void letBSayHi() { member_.sayHi(); }
private:
class B {
public:
void sayHi() { std::cout << "hola!"; }
};
B member_;
};
Addendum re: comment: The implementation can be separated from the declaration like this:
Header:
class A {
public:
void letBSayHi();
private:
class B {
public:
void sayHi();
};
B member_;
};
Source file:
void A::letBSayHi() { member_.sayHi(); }
void A::B::sayHi() { std::cout << "hola!\n"; }
// ^^^^-- interesting part here
Well, if you want to include, why not?
class A {
#include "B.hpp"
...
};
This question already has answers here:
Inherit interfaces which share a method name
(5 answers)
Closed 10 years ago.
Have code as below
// A has a virtual function F().
class A
{
public:
virtual void F() {};
};
// The same for B.
class B
{
public:
virtual void F() {};
};
// C inherits A and B.
class C : public A, public B
{
public:
// How to implement the 2 virtual functions with the same name but from
// different base classes.
virtual F() {...}
};
Note that there is a default implementation of F() in the base classes.
Thanks to Jan Herrmann and Spook. Is the below a simpler solution if we have to use some extra helpers?
#include <iostream>
// A has a virtual function F().
class A
{
private:
virtual void A_F() {}
public:
void F() {return A_F();};
};
// The same for B.
class B
{
private:
virtual void B_F() {}
public:
void F() {return B_F();};
};
// C inherits A and B.
class C : public A, public B
{
private:
virtual void A_F() {std::cout << "for A\n";}
virtual void B_F() {std::cout << "for B\n";}
};
int main()
{
C c;
c.A::F();
c.B::F();
return 0;
}
class C_a
: public A
{
virtual void F_A() = 0;
virtual void F() { this->F_A() };
};
class C_b
: public B
{
virtual void F_B() = 0;
virtual void F() { this->F_B() };
};
class C
: public C_a
, public C_b
{
void F_A() { ... }
void F_B() { ... }
};
If I'm remembing right the ISO committee thought about this problem and discussed a change of the language. But then ... somebody found this nice way to solve this problem :-)
Your second solution is better in case your are able to change your class hierarchy. You may have a lock at http://www.gotw.ca/publications/mill18.htm for a description why it is better.
Try this:
#include <cstdio>
class A
{
public:
virtual void F() = 0;
};
class B
{
public:
virtual void F() = 0;
};
class C : public A, public B
{
void A::F()
{
printf("A::F called!\n");
}
void B::F()
{
printf("B::F called!\n");
}
};
int main(int argc, char * argv[])
{
C c;
((A*)(&c))->F();
((B*)(&c))->F();
getchar();
return 0;
}
Take into consideration though, that you won't be able to call F from C's instance (ambiguous call).
Also, F has to be abstract in A and B, otherwise you'll get compilation error:
Error 1 error C3240: 'F' : must be a non-overloaded abstract member function of 'A'
Why is it that in the code below the compiler complains that PureAbstractBase is an ambiguous base class of MultiplyInheritedClass? I realize I have two copies of the PureAbstractBase in MultiplyInheritedClass and that FirstConreteClass and SecondConreteClass should be derived virtually because they're the middle row of the diamond (and that does indeed fix the problem with the code below). But even though I have two copies of the interface why is it that the code in MultiplyInheritedClass does not just override both and unambiguously pick the interface class defined in MultiplyInheritedClass?
#include <iostream>
using namespace std;
class PureAbstractBase {
public:
virtual void interface() = 0;
};
// I know that changing the following line to:
// class FirstConcreteClass : public virtual PureAbstractBase {
// fixes the problem with this hierarchy
class FirstConcreteClass : public PureAbstractBase {
public:
virtual void interface() { implementation(); }
private:
void implementation() { cout << "This is object FirstConcreteClass\n"; }
};
// I know that changing the following line to:
// class SecondConcreteClass : public virtual PureAbstractBase {
// fixes the problem with this hierarchy
class SecondConcreteClass : public PureAbstractBase {
public:
virtual void interface() { implementation(); }
private:
void implementation() { cout << "This is object SecondConcreteClass\n"; }
};
class MultiplyInheritedClass : public FirstConcreteClass,
public SecondConcreteClass {
public:
virtual void interface() { implementation(); }
private:
void implementation() { cout << "This is object MultiplyInheritedClass\n"; }
};
Further, why do I not have issues with the following hierarchy? Doesn't the ConcreteHandler class have three copies of the AbstractTaggingInterface in this case? So why doesn't it have the same issue as the example above?
#include <iostream>
using namespace std;
class AbstractTaggingInterface {
public:
virtual void taggingInterface() = 0;
};
class FirstAbstractHandler : public AbstractTaggingInterface {
public:
virtual void taggingInterface() { cout << "FirstAbstractHandler\n"; }
virtual void handleFirst() = 0;
};
class SecondAbstractHandler : public AbstractTaggingInterface {
public:
virtual void taggingInterface() { cout << "SecondAbstractHandler\n"; }
virtual void handleSecond() = 0;
};
class ThirdAbstractHandler : public AbstractTaggingInterface {
public:
virtual void taggingInterface() { cout << "ThridAbstractHandler\n"; }
virtual void handleThird() = 0;
};
class ConcreteHandler : public FirstAbstractHandler,
public SecondAbstractHandler,
public ThirdAbstractHandler {
public:
virtual void taggingInterface() = { cout << "ConcreteHandler\n"; }
virtual void handleFirst() {}
virtual void handleSecond() {}
virtual void handleThird() {}
};
I am trying to wrap my head around all of this because I had a conversation with a colleague recently where he claimed that if you were inheriting from pure virtual classes (interfaces) without any data members then virtual inheritance was not necessary. I think understanding why the former code example does not work and the latter does would go a long way to getting this straight in my head (and clear up what exactly he meant by his comment). Thanks in advance.
You need virtual inheritance to overcome the diamond-ambiguity:
class FirstConcreteClass : public virtual PureAbstractBase { ... };
class SecondConcreteClass : public virtual PureAbstractBase { ... };
Long-winded explanation: Suppose you have this:
// *** Example with errrors! *** //
struct A { virtual int foo(); };
struct B1 : public A { virtual int foo(); };
struct B2 : public A { virtual int foo(); };
struct C: public B1, public B2 { /* ... */ }; // ambiguous base class A!
int main() {
A * px = new C; // error, ambiguous base!
px->foo(); // error, ambiguous override!
}
The inheritance of the virtual function foo is ambiguous because it comes in three ways: from B1, from B2 and from A. The inheritance diagram forms a "diamond":
/-> B1 >-\
A-> ->C
\-> B2 >-/
By making the inheritance virtual, struct B1 : public virtual A; etc., you allow any baseclass of C* to call the correct member:
struct A { virtual int foo(); };
struct B1 : public virtual A { virtual int foo(); };
struct B2 : public virtual A { virtual int foo(); };
struct C: public B1, public B2 { virtual int foo(); };
We must also define C::foo() for this to make sense, as otherwise C would not have a well-defined member foo.
Some more details: Suppose we now have a properly virtually-inheriting class C as above. We can access all the various virtual members as desired:
int main() {
A * pa = new C;
pa->foo(); // the most derived one
pa->A::foo(); // the original A's foo
B1 * pb1 = new C;
pb1->foo(); // the most derived one
pb1->A::foo(); // A's foo
pb1->B1::foo(); // B1's foo
C * pc = new C;
pc->foo(); // the most derived one
pc->A::foo(); // A's foo
pc->B1::foo(); // B1's foo
pc->B2::foo(); // B2's foo
pc->C::foo(); // C's foo, same as "pc->foo()"
}
Update: As David says in the comment, the important point here is that the intermediate classes B1 and B2 inherit virtually so that further classes (in this case C) can inherit from them while simultaneously keeping the inheritance from A unambiguous. Sorry for the initial mistake and thanks for the correction!
Your first example fails because the compiler cannot disambiguate between the three implementations of implementation(). You are overriding that method in MultiplyInheritedClass, which actually overrides both FirstConcreteClass::implementation and SecondConcreteClass::implementation (once virtual, always virtual). However, both virtual calls still exist in the interface of MultiplyInheritedClass, which makes the call ambiguous at the call site.
The reason that your example works without virtual inheritance is that there is no conflicting implementation of the common base class. Put another way:
class Base
{
public:
void DoSomething() {
std::cout << "TADA!";
}
}
class One : public Base
{
//...
}
class Two : public Base
{
//...
}
class Mixed : public One, public Two
{
//...
}
int main()
{
Mixed abc;
abc.DoSomething(); //Fails because the compiler doesn't know whether to call
// One::DoSomething or Two::DoSomething, because they both
// have implementations.
//In response to comment:
abc.One::DoSomething(); //Succeeds! You removed the ambiguity.
}
Because your example has all pure virtual functions, there's no multiple implementations which the compiler needs to disambiguate. Therefore, only one implementation exists, and the call is unambiguous.
I tried both of the question codes and they worked fine when instantiating an object of the multi-inherited class. It didn't work only with polymorphism, like this for example:
PureAbstractBase* F;
F = new MultiplyInheritedClass();
And the reason is clear: it doesn't know to which copy of the Abstract base class it should be linked (sorry for bad expressions, I understand the idea but can't express it). And since inherting virtaully makes only one copy exist in the derived class, then it's fine.
Also the code of Billy ONeal is not clear at all, what should we place instead of the comments?
If we place:
public:
void DoSomething()
{ std::cout << "TADA!"; }
it works fine, because of no virtuality.
I work on Visual Studio 2008.
Why not do it like this (suggested in Benjamin Supnik's blog entry):
#include <iostream>
class PureAbstractBase {
public:
virtual void interface() = 0;
};
class FirstConcreteClass : public PureAbstractBase {
public:
virtual void interface() { implementation(); }
private:
void implementation() { std::cout << "Fisrt" << std::endl; }
};
class SecondConcreteClass : public PureAbstractBase {
public:
virtual void interface() { implementation(); }
private:
void implementation() { std::cout << "Second" << std::endl; }
};
class MultiplyInheritedClass : public FirstConcreteClass,
public SecondConcreteClass
{
public:
virtual void interface() { implementation(); }
private:
void implementation() { std::cout << "Multiple" << std::endl; }
};
int main() {
MultiplyInheritedClass mic;
mic.interface();
FirstConcreteClass *fc = &mic; //disambiguate to FirstConcreteClass
PureAbstractBase *pab1 = fc;
pab1->interface();
SecondConcreteClass *sc = &mic; //disambiguate to SecondConcreteClass
PureAbstractBase *pab2 = sc;
pab2->interface();
}
which gives:
Multiple
Multiple
Multiple
This way:
no virtual bases are involved (do you really need them?)
you can call the overriden function via a an instance of the MultiplyInheritedClass
ambiguity is removed by a two-stage conversion
Is there a nice way to call A::foo() from B::bar() in the following sample?
class A {
protected:
void foo() {}
};
class B : public A {
public:
void bar(A& a) { // edit: called with &a != this
a.foo(); // does not work
}
};
I can't think of anything other than declaring B to be a friend of A, but that could get pretty ugly with some more classes.
Any ideas?
Yes, you can use a base-class function.
class A {
protected:
void foo() {}
void do_other_foo(A& ref) {
ref.foo();
}
};
class B : public A {
public:
void bar(A& a) { // edit: called with &a != this
this->do_other_foo(a);
}
};
Why are you passing object of type A? You could do like this :
class B : public A {
public:
void bar() {
foo();
}
};
or, like this
class B : public A {
public:
void bar() {
A::foo();
}
};
Here's an approach to giving "protected" like access, allowing calls by any derived classes or object.
It uses a protected token type, required to un-lock privileged methods:
struct A
{
protected:
//Zero sized struct which allows only derived classes to call privileged methods
struct DerivedOnlyAccessToken{};
public: //public in the normal sense :
void foo() {}
public: //For derived types only :
void privilegedStuff( DerivedOnlyAccessToken aKey );
};
struct B: A
{
void doPrivelegedStuff( A& a )
{
//Can create a token here
a.privilegedStuff( DerivedOnlyAccessToken() );
}
};
int _tmain(int argc, _TCHAR* argv[])
{
A a;
a.foo();
a.privilegedStuff( A::DerivedOnlyAccessToken() ); // compile error.
B b;
b.doPrivelegedStuff( a );
return 0;
}
This is not my idea. I read it some place. Sorry I dont recall who's cunning idea it was.
I expect the compiler can elide the aKey parameter.