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.
Related
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
Consider this trivial C++11 inheritance example:
class A
{
public:
virtual void func() = 0;
};
class B : public A
{
public:
void func() { func1(); /* Wish this could be func1() or func2()! */ };
void func1() { /* Does one thing */ };
void func2() { /* Does another thing */ };
};
void doSomeStuff(A &a)
{
a.func();
}
int main()
{
B b;
doSomeStuff(b);
return 0;
}
I'm trying to make it so that I don't have to modify (or duplicate) class A's definition or the function doSomeStuff, but I want the invocation of a.func() to call either func1() or func2() of B. Ideally I'd change the line doSomeStuff(b) to something like doSomeStuff(b.butWithFunc1) but I'd also be OK with some way to modify B's version of func() so that it can make the decision internally to call func1 or func2 based on some parameter.
The same object of type B may have to sometimes call func1 or func2 during an invocation of func, so I can't use a persistent member of class B to decide. Adding a parameter to func() would make this trivial as well, but that's not something I can do either.
I'm kind of wondering if there's some way to add to class B a function that returns a mutated version of class B which calls func2() from func(), or if I can play some tricks with function pointers or something. However, something tells me I'm Doing It Wrong and the obvious solution is staring me in the face.
If it helps for context, class A is similar to a std::lock_guard, and it works fine for things like semaphores and mutexes (for which there is only one definition of lock and unlock), but class B in this example is a R/W lock - so there's a "readLock" and "writeLock", and I'd like to be able to say something like "auto lock this RW lock as a read lock" without having to duplicate/break the auto lock code.
For instance:
{
A_AutoSem(myMutex); // calls lock() on myMutex
//... do some stuff
// end of the block, ~A_AutoSem calls unlock on myMutex
}
{
A_AutoSem(B_RWLock); // how do I say here "call readLock"?
// ... do some stuff
// end of the block ~A_AutoSem should call "readUnlock" on B_RWLock
}
Simply define some additional classes to call func1() and func2(), and then pass those classes to doSomeStuff() instead of passing B directly.
Try something like this:
class A
{
public:
virtual void func() = 0;
};
class B
{
public:
void func1() { /* Does one thing */ };
void func2() { /* Does another thing */ };
};
class C1 : public A
{
private:
B &m_b;
public:
C1(B &b) : m_b(b) {}
void func() override { m_b.func1(); }
};
class C2 : public A
{
private:
B &m_b;
public:
C2(B &b) : m_b(b) {}
void func() override { m_b.func2(); }
};
void doSomeStuff(A &a)
{
a.func();
}
int main()
{
B b;
{
C1 c(b);
doSomeStuff(c);
}
{
C2 c(b);
doSomeStuff(c);
}
return 0;
}
Live Demo
Alternatively:
class A
{
public:
virtual void func() = 0;
};
class B
{
private:
void func1() { /* Does one thing */ };
void func2() { /* Does another thing */ };
public:
class C1 : public A
{
private:
B &m_b;
public:
C1(B &b) : m_b(b) {}
void func() override { m_b.func1(); }
};
class C2 : public A
{
private:
B &m_b;
public:
C2(B &b) : m_b(b) {}
void func() override { m_b.func2(); }
};
};
void doSomeStuff(A &a)
{
a.func();
}
int main()
{
B b;
{
B::C1 c(b);
doSomeStuff(c);
}
{
B::C2 c(b);
doSomeStuff(c);
}
return 0;
}
Live Demo
I am very new to c++ so I am trying to get a feeling of how to do things the right way in c++. I am having a class that uses one of two members. which one gets determined at instantiation. It looks something like
main() {
shared_pointer<A> a = make_shared<A>();
if ( checkSomething ) {
a->setB(make_shared<B>());
} else {
a->setC(make_shared<C>());
}
a->doStuff();
class A {
public:
doStuff() {
/*here I want to do something like call
m_b->doStuff() if this pointer is set and m_c->doStuff() if
that pointer is set.*/
}
setB( B* p ) { m_b = p; }
setC( C* p ) { m_c = p; }
B* m_b;
C* m_c;
}
}
B and C are some classes with doStuff() member function
There are many members like doStuff. Ideally I would avoid checking for nullptr in each of them. What is the best/most efficient/fastest way to create a switch between those two members?
Is there a way to use a static pointer so that I have a member
static **int m_switch;
and do something like
m_switch = condition ? &m_b : &m_c;
and call
*m_switch->doStuff();
Does the compiler here also replace the extra pointer hop because it is a static?
Is there any other smart way to do those switches?
Normally, class A would be an interface class, which both B and C would inherit and implement. But it sounds like you cannot do this for whatever reason.
Since you want to emulate this, you can start by making the interface:
class A_interface
{
public:
virtual void doStuff() = 0;
virtual void doThings() = 0;
virtual void doBeDoBeDo() = 0;
};
And then you make a template wrapper:
template< class T >
class A : public A_interface
{
public:
void doStuff() override { target.doStuff(); }
void doThings() override { target.doThings(); }
void doBeDoBeDo() override { target.doBeDoBeDo(); }
private:
T target;
};
This essentially does half of what your own example class A was trying to do, but now you can use a common interface. All you need to do is construct the correct templated version you want:
std::shared_ptr<A_interface> a;
if( checkSomething ) {
a = std::make_shared<A<B>>();
} else {
a = std::make_shared<A<C>>();
}
a->doStuff();
You need to have both members implement a common interface to use them similarly. But in order to do that, you need to define the interface and relay the calls to the B and C classes.
// existing classes
class B
{
public:
void doStuff() { std::cout << "B"; }
};
class C
{
public:
void doStuff() { std::cout << "C"; }
};
// define your interface
class I
{
public:
virtual void doStuff() = 0;
};
// new classes
class D : public B, public I
{
public:
void doStuff() override { B::doStuff(); }
};
class E : public C, public I
{
public:
void doStuff() override { C::doStuff(); }
};
// your A class
class A
{
public:
D* b = nullptr; // now type D
E* c = nullptr; // now type E
// your toggle
I* getActive()
{
if (b)
return b;
else
return c;
}
// simple doStuff() function
void doStuff()
{
getActive()->doStuff();
}
};
int main()
{
A a;
if (true)
a.b = new D; // need to initialize as D
else
a.c = new E; // need to initialize as E
a.doStuff(); // prints B
}
But typing this up made me realize that defining D and E could get really tiresome and against what you're trying to save. However, you can define a template to create them like #paddy has done.
There's no one-size-fits-all solution for your problem. What to use depends on your particular problem. A few possible answers:
Interfaces
Strategy Pattern
Pointers (to hold a function or class which implements doStuff)
An interface is like a contract. Any class which inherits from the interface must implement its members. For instance,
class IDoesStuff
{
public:
virtual ~IDoesStuff() {};
virtual void DoStuff() = 0;
};
Can now be used by other classes:
class Foo : public IDoesStuff
{
public:
virtual void DoStuff()
{
// ....
}
};
class Bar : public IDoesStuff
{
public:
virtual void DoStuff()
{
// ....
}
};
And now, in general, one may do:
Foo foo;
IDoesStuff *stuffDoer= &foo;
stuffDoer->doStuff();
This can be used in your particular use case as follows:
class A
{
IDoesStuff *stuffDoer; // Initialize this at some point.
public:
void doStuff() { stuffDoer->doStuff(); }
};
First you must change your memebr variables m_b and m_c to std::shared_ptr.
Add a member variable of type std::function(void()) to hold the target function you want to call. In your sample it is do_stuf.
In your setter functions you can bind target function to your std::function and in do_stuf just call std::function.
(You need a C++11 compiler)
class B
{
public:
void doStuff()
{
}
};
class C
{
public:
void doStuff()
{
}
};
class A
{
public:
void doStuff()
{
m_target_function();
}
void setB(std::shared_ptr<B> p)
{
m_b = p;
m_target_function = std::bind(&B::doStuff, m_b.get());
}
void setC(std::shared_ptr<C> p)
{
m_c = p;
m_target_function = std::bind(&C::doStuff, m_c.get());
}
std::shared_ptr<B> m_b;
std::shared_ptr<C> m_c;
std::function<void()> m_target_function;
};
int _tmain(int argc, _TCHAR* argv[])
{
std::shared_ptr<A> a = std::make_shared<A>();
bool use_B = false;
if (use_B)
{
a->setB(std::make_shared<B>());
}
else
{
a->setC(std::make_shared<C>());
}
a->doStuff();
}
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 C++ compiler gives this error? Why i can access lol() from B, but can not access rofl() [without parameters]. Where is the catch?
class A
{
public:
void lol(void) {}
void rofl(void) { return rofl(0);}
virtual void rofl(int x) {}
};
class B : public A
{
public:
virtual void rofl(int x) {}
};
int _tmain(int argc, _TCHAR* argv[])
{
A a;
a.lol();
a.rofl(1);
a.rofl();
B b;
b.lol();
b.rofl(1);
b.rofl(); //ERROR -> B::rofl function does not take 0 arguments
return 0;
}
The B::rofl(int) 'hides' the A::rofl(). In order to have A's rofl overloads, you should declare B to be using A::rofl;.
class B : public A {
public:
using A::rofl;
...
};
This is a wise move of C++: it warns you that you probably also need to override the A::rofl() method in B. Either you do that, or you explicitly declare that you use A's other overloads.