I have a class A that should call a non-static class method from an interface class B, with signature expressed by, say, the following function pointer:
bool (B::*check)(int) const
Such method would be implemented by a set of classes {C} implementing B, each with multiple methods matching the above signature. I therefore need to bind the callback from A towards B, which in turn would delegate to the chosen method from C.
Edited with some code:
This is a sketch of what I have in mind. Beware that this is only an example of the requirement above, nothing in the organization of the code is mandatory outside, perhaps, class A.
class B {
public:
bool check(int val) const {
// call to a binded method with a given signature (sig) on a Cx class
...
}
};
class C1: public B {
...
// a method implementing the (sig) signature
// another method implementing the (sig) signature
};
class C2: public B {
...
// a method implementing the (sig) signature
// another method implementing the (sig) signature
};
class A {
public:
...
private:
bool result;
int val;
void call_check(B const& b) const {
result = b.check(val);
}
...
};
It that possible in C++? Or equivalently, what would be a solution that allows A to know of class B only?
To my puzzlement, I haven't found a solution around for this very specific need.
Massive Edit
I think I got what you want, based on some heavy type-casting.
Note that I do NOT recommend this technique. Although my example works, I believe there are some big pitfalls here that could really screw things up.
As before, Class A can accept both a method of the proper signature and an object (of type B, or derived from type B, such as your C classes), and call the specified method on the specified object.
Class B does not actually have any methods at all, and only acts as a common base-class for the two classes C1 & C2.
At the bottom is a main that demonstrates how this is used. I left out the implementation of the two SetCallback*** methods, as they're trivial.
class B
{ public: // Has nothing, only serves as base-class for C1 and C2.
};
class C1: public B
{
public: bool DoThis(int x) const { return true; }
};
class C2: public B
{
public: bool DoThat(int x) const { return false; }
};
class A
{
private:
bool (B::*m_check)(int) const;
B* m_Obj;
public:
void SetCallbackFunction(bool (B::*fnc)(int) const)
{ m_check = fnc; }
void SetCallbackObject(B* pB)
{ m_Obj = pB; }
bool InvokeCallback(int val)
{
return (m_Obj->*m_check)(val);
}
};
int _tmain(int argc, _TCHAR* argv[])
{
A a;
C1 c;
bool (C1::*func)(int) const;
bool (B::*b_func)(int) const;
func = &C1::DoThis;
b_func = (bool (B::*)(int) const)(func); // Dangerous Typecasting. Use caution!
a.SetCallbackFunction(b_func);
a.SetCallbackObject((B*)(&c)); // A simpler, safer typecast.
a.InvokeCallback(5); // Ends up calling C1::DoThis.
_getch();
return 0;
}
The simplest thing you can do is not to use a member function pointer, but rather a higher order construct like function (either boost or C++11) and register the callbacks with bind (again, boost or C++11).
Pointers-to-member-functions are available, and do exactly what you want. However, just be aware that they are not actually "pointers", but are "pointer-like", since it is possible that proper lookup/calling must go through the "vptr" table(s) associated with a class that may possibly have more-than-one-parent.
In short: Yes, you can have it. If you implement in a template, you do not need to include the target headers (but you would need to implement the target class headers at the point of code expansion). If you implement as a non-template, then you could forward-declare the member functions and get it to work. Or, you could simply include the target class-type headers.
Since multiple target functions are available, yes, at the point of actual binding, you must include the header (you don't need the header if this is a template implementation):
class MyA {
public:
bool foo1(int) const;
bool foo2(int) const;
};
void MyFunc(void) {
bool (MyA::*my_ptr_to_func)(int) const;
my_ptr_to_func = &MyA::foo2;
MyA my_a;
// call it
if((my_a.*my_ptr_to_func)(42))
{
// ...
}
}
[UPDATE], based on your updated code, it seems like you merely want to make "bool B::check(int) const" to be "virtual" in the base class, and override/re-implement that function in the derived "C1" and "C2" classes?
Yes, the virtual function will be called (the implementation in the C1 and C2 classes), even though your pointer was originally to the B::check(int) function. This works, and is exactly why a pointer-to-member-function is not exactly a pointer, but is pointer-like (to permit your call to correctly execute the virtual code in the derived classes).
So, no fear: It will work, just put "virtual" on B::check(int) in the base.
It sounds like you want to use the observer pattern to allow A to hold a vector of function pointers of type bool (B::*check)(int) const.
Classes in {C} could thus register through the observer pattern to A. I don't see why you need an interface, B, explicitly if you use this form of pattern. The interface will be guaranteed by the vector of function pointers requiring the signature of your chosen function pointer.
Related
I was trying to create two classes, the first with a non-const implementation of the functions, the second with a const implementation. Here is a small example:
class Base {
protected:
int some;
};
class A : public virtual Base {
const int& get() const {
return some;
}
};
class B : public virtual Base {
int& get() {
return some;
}
};
class C : public A, B {};
C test;
test.get(); // ambiguous
The call to the get function is ambiguous. No matter that the const version needs to match more requirements. (Calling get on const C is ambiguous as well, but there is one possible function to call.)
Is there a reason for such behaviour in the standard? Thanks!
Ambiguity occurs when compiler tries to figure out to what entity does the name get refer to, prior to overload resolution. It can be a name of function from class A or from class B. In order to build a list of overloads complier needs to select just one of the classes to pull functions from. In order to fix it you can bring that name from both of the base classes into derived class (and make them public):
class C : public A, public B { public: using A::get; public: using B::get; };
The problem is that you don't actually have one unified overload-set, in which the mutable variant would be unambiguously best, but two distinct overload-sets, in A and B, and the compiler will not automatically merge them.
Put
using A::get;
using B::get;
in C to merge the overload-sets and thus resolve the ambiguity.
I have a derived class where I want one of the functions to override its version in the base class, but have a different signature.
Simple example:
#include "stdio.h"
bool use_foo = false;
class Foo {
public:
virtual int func(double x) { printf ("%f in Foo!\n", x); }
};
class Bar : public Foo {
public:
int func(short x) { printf ("%d in Bar!\n", x); }
};
int main () {
Foo* A;
if (use_foo)
A = new Foo;
else
A = new Bar;
A->func(2);
return 0;
}
The above code would call the base class copy even though A was allocated as the derived class:
> g++ test.cpp -o test -O3 && ./test
2.000000 in Foo!
Because (as far as my understanding goes) the argument can be converted to match the base class signature, and the derived class doesn't override it because of this difference (but wouldn't it hide it in that case?). If I change the base class function to have short as argument as well, the derived class does manage to override it.
Is there a simple way to convince the call to use the correct function based on the pointer? I could add another function like this:
class Bar : public Foo {
public:
int func2(short x) { printf ("%d in Bar!\n", x); }
int func(double x) { func2(x); }
};
But then I would convert the arguments all the time (short->double->short), and this function is performance critical. Is there a better way?
These function signatures are not identical:
virtual int func(double x) {...} // base class
int func(short x) {...} // derived class
One uses double parameter, the other uses short. For overriding to occur several conditions must be met. Identical parameter types of the base and derived functions being one of them. Bellow is the excerpt from the "Modern Effective C++" book by Scott Meyers on all the requirements:
• The base class function must be virtual.
• The base and derived
function names must be identical (except in the case of destructors).
• The parameter types of the base and derived functions must be
identical.
• The constness of the base and derived functions must be
identical.
• The return types and exception specifications of the base
and derived functions must be compatible.
Alternatively, make the signatures the same and perform the casting inside a derived function body:
int func(double x) override {
short temp = static_cast<short>(x);
// ...
}
What sense does this make anyway? The reason you use a virtual function is that the caller should only be required to know the base class, and thus only the base-class signature.
In other words, code which has, say, a Foo& or a Foo* or a std::unique_ptr<Foo>, only knows about the double version of your function anyway. It will pass a double when it calls func, because what else should it do?
Perhaps what you really want to do is the subclass implementation of the function to convert the double to a short. Here's an example for that, which also gets rid of the printf in favour of a type-safe C++ stream:
class Bar : public Foo {
public:
int func(double x) { std::cout << static_cast<short>(x) << " in Bar!\n"; }
};
Note that since C++11, you are encouraged to use override to mark overriding functions.
and this function is performance critical.
Should a performance-critical function be virtual at all?
Have you actually measured the speed? Is there a noticeable delay? Or are computers too fast anyway?
I have several classes D with public sections of the form:
class D
{
public:
D& foo();
void bar(D&);
}
I'd like to create a single abstract class from which they all derive.
My (naive) attempt was:
// in .h file
class B
{
public:
virtual B& foo() = 0;
virtual void bar(B&) = 0;
}
class D : public B
{
public:
D& foo() override;
void bar(D&) override;
}
// in .cpp file
D& D::bar() {return *(new D());}
void D::foo(D& d) {}
This failed to compile for (what I eventually realized was) a fairly sensible reason: Any function overriding the function
void bar(B&)=0;
must be defined for any parameter which is a reference to type B. The supplied candidate
virtual void bar(D&) override;
is only defined for (the smaller collection) of parameters which are references to type D.
Note that this is not a problem with the function foo. Indeed, if you comment out the three lines with bar, everything compiles fine.
I think that the technical explanation for this phenomenon is that C++ does not support covariance in parameters (but it does support contravariance in parameters).
The answer to the post C++ covariance in parameters suggests that I can't define an interface (i.e. an abstract class) for my classes D.
Is there some simple or conventional way to create a single "interface" for all my classes D? Alternatively, perhaps there is a different design pattern for hiding the different implementations of these classes.
Thanks in advance for your comments and suggestions.
dan
You can't, and for good reason. A derived class can't add preconditions that are more restrictive than the interface it derives from without breaking every principle of OOP that exists. By requiring the parameter to be more specific in your implementation of the interface this is exactly what you are doing.
An argument could be made that something like this could be useful:
struct IfaceA {};
struct IfaceB : IfaceA {};
struct Base { void f(IfaceB &); };
struct Derived : Base { void f(IfaceA &); };
This lessens preconditions rather than increase them, so it's OK. It's simply not done in C++, or any other language I'm aware of for that matter, so you just can't do it.
In both cases you can make an overload with the alternative parameter type and call the overridden version.
It's the opposite case with return types. Return values are post-conditions. You can make post conditions more specific, but can't make them more broad. So you can return your derived type but can't broaden it by returning a more abstract type. C++ implements covariant returns though at least one, very commonly used compiler does it very badly so that there are numerous bugs.
Based on the code that you have provided you have tried to override two diferent function signatures.
The best option you have is use the same signature, and then cast the result.
A simple example,
// in .h file
class B
{
public:
virtual B* foo() = 0;
virtual void bar(B*) = 0;
};
class D : public B
{
public:
B* foo() override;
void bar(B*) override;
};
// in .cpp file
B* D::foo()
{
D* p=new D();
return p;
}
void D::bar(B* d)
{
D* casted=dynamic_cast<D*>(d);
}
int main(void)
{
D son;
B* father=dynamic_cast<B*>(son.foo());
}
I hope that this can solve your problem, or at least give you a clue.
Could you use a templated base class?
template <typename Deriving>
struct Base {
virtual Deriving& foo() = 0;
virtual void bar(Deriving&) = 0;
};
struct Deriving : public Base<Deriving> {
...
};
You don't have a single interface class, but there is a single interface template, which is sometimes versatile enough.
I also have a similar design question now in my work assignment. I have a base class like
class base
{
protected:
update()
{
// do some stuff with a and b, call it as action A
}
int a, b;
};
class derived : public base
{
protected:
update()
{
// want to do the same action A , but with varaiables c and d
}
int c, d;
};
and the requirement is, derived class requires both the operations , such as action on "a and b" AND "c and d" aslo. Hence , is it okay to design a method like update(int, int) , so that I can pass parameters as and when required "a and b" AND "c and d" and perform action on them .And I know that I can write a helper method to perform that action, but this action is specific to this class I cant separate it from this. Can I have any other better alternative for this.
In realtime its a bigger class and the action also not on integers ,its on some objects in turn, and the varibales should be related to the class.
You can call the base class implementation from the derived class implementation. Just call base::update(). Look here for example.
Yes that is perfectly valid:
class base
{
protected:
void update()
//^^^^ You forgot the return type.
{
doUpdate(a, b);
}
void doUpdate(int& x, int& y)
{
// do some stuff with x and y
// Because x and y are passed by reference they affect the original values.
}
private: // Should probaly make the member vars private
int a, b;
};
class derived : public base
{
protected:
void update()
//^^^^ You forgot the return type.
{
doUpdate(c, d);
}
private: // Should probaly make the member vars private
int c, d;
};
I would revisit whether your class derived has an is-a relationship (as you show) or a has-a relationship, like this:
class contains
{
protected:
base x, y;
update() { x.update(); y.update(); }
};
What you're asking is technically feasible, just define
void update(int& a, int &b)
and inside the update body forgot about the class memebrs and always refer to the parameters and call it as
update(a,b) or update(c,d).
The point, here, is to understand if update is really a member function (that requires also to access other member variables) or just a static member (that leaves in the class space, but doesn't see class members itself) and if the relation between the classes is correct (that merely means embedding vs inheritance). But these aspects should be based on consideration other than just the ones related on a single call...
Here are the requirements posed by my application. I have a class A, that accepts a function pointer say cFunc, Basically in my implementation of A, I have it call cFunc multiple times.
The cFunc pointer itself should point to different functions depending upon the application. Thus for each application I create a class with the same function definition as cFunc, however I cannot assign the class's member function to this pointer
class A {
typedef double (*Def_CFunc)(std::vector<double>);
A(Def_CFunc _cFunc) { // Some implementation}
// Other Functions
};
class B { double someFunc(std::vector<double> b); };
class C { double someOtherFunc(std::vector<double> a); };
int main () {
B firstObj;
C secondObj;
// Depending upon the situation, I want to select class B or C
double (*funcPointer)(std::vector<double>) = firstObj.someFunc; // Error in this line of code
A finalObj(funcPointer);
}
So how do I make it such that any class with a member function of the given format can be used to initialize the class A?
I'm not sure what exactly your requirements are, but it looks like you want an interface (or abstract base class in C++ lingo).
If both B and C inherit from a common base class, you can pass a pointer to this base class and invoke functions on it:
class I { virtual double func(std::vector<double> a) = 0; }
class B : public I { double func(std::vector<double> a); };
class C : public I { double func(std::vector<double> a); };
You can pass an I* pointer to A and just use i->func.
Pointer to member function has different syntax than pointer to ordinary function and can only point to a method of one given class. To be able to point to methods in different classes use boost::function or if C++11 is available use std::function. These can hold any method or function of a given signature.
What you need is std::function together with either std::bind or lambda expressions (or the Boost equivalent of the first two), because member function pointers don't allow you to do that.
You can do it using std::bind + std::function. Lets write some template class wrapper, that takes any static type as input. Then use this wrapper in free function switch_obj. Usage is very simple.
typedef std::function<double(std::vector<double>)> my_foo;
template<class C>
struct switcher
{
static my_foo convert(C* obj)
{
return my_foo( std::bind(&C::someFunc,obj,std::placeholders::_1) );
}
};
template<class T>
my_foo switch_obj(T* obj)
{
return switcher<T>::convert(obj);
}
void main()
{
B firstObj;
C secondObj;
auto f = switch_obj(&firstObj);
A a(f);
}