C++ usefulness of a pointer to non-static method - c++

As I understood pointers to non-static methods, they're no more useful than for providing an alias mechanism for a certain method. For example, having an object with three methods
class Provider
{
public:
int A(int in);
int B(int in);
int C(int in);
}
and a consumer that requires a pointer to a provider method (be it A, B or C). Having a controller that gives a pointer to one of the 3 methods to the so-called consumer, we can write something in the consumer code that uses a Provider instance and the pointer to either A, B or C, depending on what the controller sent.
If this is all that a pointer to a non-static method in C++ can do, is there still a way of providing a more "intelligent" pointer to an object's method, without sending the object along with that method pointer to a consumer? In the affirmative case, what's the idiom/mechanism called (even a way to simulate this qualifies as an answer I'm interested in).

Your concept of member functions pointers is correct in general.
Member functions pointers are actually very useful with conjunctions to such helpers, as std::bind, or std::function. Raw member function pointers are usually ugly.
As for your example,
Your consumer can accept std::function<return_type(args)> and you can pass binding of object and its member function to such consumer.
such structs as std::bind also allows realization of such concepts as partial specialization and currying.

The whole point of a "pointer to member function" is so you can call a named method on any object (of the correct class). So, no, there is no way to "hide" the object reference inside the pointer.
You can always write your own wrappers for stuff like this; that's what the various callback mechanisms for C++ do to give you a more convenient API for the application at hand.

You dont have to glue pointer to object with pointer to method to be called, you can provide pointer to instance any time, ie:
class CClass {
public:
void func(int a) {}
};
///
std::function<void(CClass&, int)> call_func = &CClass::func;
///
CClass cls1;
CClass cls2;
call_func(cls1, 1);
call_func(cls2, 2);

Related

How to pass unique_ptr by reference polymorphically?

I have a pure virtual class Base and some derived classes ChildA (A/B/C etc):
class Base {
...
}
class ChildA : public Base {
...
}
I need specific control of the ownership of these child classes, so I spawn them via factory functions and std::unique_ptr.
At some point during their creation/setup, I need to modify them (not make copies or change ownership) in a manner that is common to all of the derived classes, so I want to use a function that accepts their base type and takes by reference:
void modifyInstance(std::unique_ptr<Base>& baseInst);
But when I try to use this function like so:
bool childAFactory(std::unique_ptr<ChildA>& buffer)
{
buffer = std::make_unique<ChildA>();
modifyInstance(buffer);
}
I get this error:
error: non-const lvalue reference to type 'unique_ptr<Base>' cannot bind to a value of unrelated type 'unique_ptr<ChildA>'
Is it not possible to take advantage of polymorphism in this particular fashion? The only similar threads I can find are where one is trying to pass by value in which case you obviously have to use std::move() and give up ownership.
I would have the function take a regular Base pointer and use unique_ptr::get() but I also need to be able to reset the pointer within the function conditionally (so the pointer and its contents need to be able to be modified, hence passing a unique_ptr by reference).
I'd do this:
bool modifyInstance(Base* baseInst);
bool childAFactory(std::unique_ptr<ChildA>& buffer)
{
buffer = std::make_unique<ChildA>();
if (!modifyInstance(buffer.get()))
buffer.reset();
}
That is, let the factory remain responsible for lifetimes, and just return an error result from modifyInstance() when the object needs to be destroyed.

C++: call (derived's) member function on base pointer of a different derived class's object

Is it "safe" (and/or portable) to call a member function (pointer) on the pointer of a base class, but the object pointed to is an instance different derived class. The member function does not access any member variables or functions of the derived class.
/* Shortened example of what happens in the client code and library */
class Base { /* ... */ }
class DerivedA : public Base {
/* ... */
public: void doSomethingA(float dt);
}
void DerivedA::doSomethingA(float dt) {
/* Does not access members. Conventionally calls/accesses statics */
cout << "dt(" << dt << ")";
}
class DerivedB : public Base { /* ... */ }
typedef void (Base::*SEL_SCHEDULE)(float);
SEL_SCHEDULE pCallback = (SEL_SCHEDULE)(&DerivedA::doSomethingA);
DerivedB db = new DerivedB();
Base *b = &db;
/* pCallback and b are saved in a list elsewhere (a scheduler) which calls */
(b->*pCallback)(0.f);
This seems to work (in MSVC/Debug mode) okay at runtime, but I'm wondering whether this is Bad (TM) - and why? (I'm yet to test this code with the compilers for Android and iOS).
Some more specifics if required: I'm building a cocos2d-x based project. Base is CCObject, DerivedA and DerivedB are subclasses of CCLayer.
The hierarchy is DerivedA and DerivedB < CCLayer < CCNode < CCObject. They're game scenes which are visible/alive at mutually exclusive times.
DerivedA has a different static function to set up playback of music which receives a CCNode caller object as a parameter and schedules another selector (doSomethingA) to begin playback and slowly fade it in using something like:
callerNode->schedule(schedule_selector(DerivedA::doSomethingA), 0.05f);
schedule_selector is what does the C-style cast. doSomethingA does not access any of its member variables or call member functions. It accesses static members and calls other static functions such as such as
CocosDenshion::SimpleAudioEngine::sharedEngine()->setBackgroundMusicVolume(sFadeMusicVolume);
The call to doSomethingA at runtime happens in CCTimer::update.
The hack is primarily to avoid duplicating code and conform to the library's callback signature (timer/scheduler system).
It's UB.
You can even use static_cast instead of the odious C-style cast, and the cast itself is quite legal. But
[Note: although class B need not contain the original member, the
dynamic type of the object on which the pointer to member is
dereferenced must contain the original member; see 5.5. —end note ] (5.2.9 12)
"The first operand is called the object expression. If the dynamic
type of the object expression does not contain the member to which the
pointer refers, the behavior is undefined" (5.5 4)
I.e., you go undefined when you call it from an object of dynamic type DerivedB.
Now, as a dirty hacks goes, it's probably not the worst (better than the manual traversing of vtables), but is it really needed? If you don't need any dynamic data, why call it on DerivedB? Base is in the library, you cannot redefine it. Callback is librarian, too, so you have to have this typedef void (Base::*SEL_SCHEDULE)(float);, OK. But why can't you define doSomething for B and make pointer to it to couple with an instance of DerivedB? You say
doSomethingA does not access any of its member variables or call
member functions. It accesses static members and calls other static
functions
But you can do it in doSomethingB as well. Or, if your callbacks are completely uncoupled from object types, and the only reason you need a member function pointer is the conformance to the library callback signature, you can make your actual callbacks non-member plain old functions, and call them from one-line members-callback conformers like DoSomething(float dt) {ReallyDoSomething(dt);}.
I'm wondering whether this is Bad (TM)
It certainly is, unless it's an override of a virtual function declared in a common base class.
If it is, then you don't need the dodgy cast; just initialise directly from &Base::DoSomethingA.
If it isn't, then the evil C cast (which here is a reinterpret_cast in disguise) allows you to apply the pointer to a type that doesn't have that member function; calling that Frankensteinian abomination could do absolutely anything. If the function doesn't actually touch the object, then there's a good chance that you won't see any ill effects; but you're still firmly in undefined behaviour.
It is not safe in general.
You have broken the type-safety system with a C-style cast of your callback in this line:
SEL_SCHEDULE pCallback = (SEL_SCHEDULE)(&DerivedA::doSomethingA);
A member function of DerivedA should operate on an instance of a DerivedA only (or something that further derives from it). You don't have one, you have a DerivedB, but because of your C-cast, your code compiled.
If your callback function had actually tried to access a member of a DerivedA you would potentially have had serious issues (undefined behaviour).
As it is the function only prints so in this case is probably not undefined, but that doesn't mean you should do it.
One typesafe way is to use a callback that takes a Base (reference) and a float and use boost::bind or std::bind to create it.
The other simple way which will probably be your answer most of the time is to just call a virtual method of Base that takes a float.

Passing shared_ptr<Derived> as shared_ptr<Base>

What is the best method to go about passing a shared_ptr of a derived type to a function that takes a shared_ptr of a base type?
I generally pass shared_ptrs by reference to avoid a needless copy:
int foo(const shared_ptr<bar>& ptr);
but this doesn't work if I try to do something like
int foo(const shared_ptr<Base>& ptr);
...
shared_ptr<Derived> bar = make_shared<Derived>();
foo(bar);
I could use
foo(dynamic_pointer_cast<Base, Derived>(bar));
but this seems sub-optimal for two reasons:
A dynamic_cast seems a bit excessive for a simple derived-to-base cast.
As I understand it, dynamic_pointer_cast creates a copy (albeit a temporary one) of the pointer to pass to the function.
Is there a better solution?
Update for posterity:
It turned out to be an issue of a missing header file. Also, what I was trying to do here is considered an antipattern. Generally,
Functions that don't impact an object's lifetime (i.e. the object remains valid for the duration of the function) should take a plain reference or pointer, e.g. int foo(bar& b).
Functions that consume an object (i.e. are the final users of a given object) should take a unique_ptr by value, e.g. int foo(unique_ptr<bar> b). Callers should std::move the value into the function.
Functions that extend the lifetime of an object should take a shared_ptr by value, e.g. int foo(shared_ptr<bar> b). The usual advice to avoid circular references applies.
See Herb Sutter's Back to Basics talk for details.
This will also happen if you've forgotten to specify public inheritance on the derived class, i.e. if like me you write this:
class Derived : Base
{
};
Instead of:
class Derived : public Base
{
};
Although Base and Derived are covariant and raw pointers to them will act accordingly, shared_ptr<Base> and shared_ptr<Derived> are not covariant. The dynamic_pointer_cast is the correct and simplest way to handle this problem.
(Edit: static_pointer_cast would be more appropriate because you're casting from derived to base, which is safe and doesn't require runtime checks. See comments below.)
However, if your foo() function doesn't wish to take part in extending the lifetime (or, rather, take part in the shared ownership of the object), then its best to accept a const Base& and dereference the shared_ptr when passing it to foo().
void foo(const Base& base);
[...]
shared_ptr<Derived> spDerived = getDerived();
foo(*spDerived);
As an aside, because shared_ptr types cannot be covariant, the rules of implicit conversions across covariant return types does not apply when returning types of shared_ptr<T>.
Also check that the #include of the header file containing the full declaration of the derived class is in your source file.
I had this problem. The std::shared<derived> would not cast to std::shared<base>. I had forward declared both classes so that I could hold pointers to them, but because I didn't have the #include the compiler could not see that one class was derived from the other.
Sounds like you're trying too hard. shared_ptr is cheap to copy; that's one of its goals. Passing them around by reference doesn't really accomplish much. If you don't want sharing, pass the raw pointer.
That said, there are two ways to do this that I can think of off the top of my head:
foo(shared_ptr<Base>(bar));
foo(static_pointer_cast<Base>(bar));

Is a pointer to a virtual member function valid in the constructor of the base class?

My question is not about calling a virtual member function from a base class constructor, but whether the pointer to a virtual member function is valid in the base class constructor.
Given the following
class A
{
void (A::*m_pMember)();
public:
A() :
m_pMember(&A::vmember)
{
}
virtual void vmember()
{
printf("In A::vmember()\n");
}
void test()
{
(this->*m_pMember)();
}
};
class B : public A
{
public:
virtual void vmember()
{
printf("In B::vmember()\n");
}
};
int main()
{
B b;
b.test();
return 0;
}
Will this produce "In B::vmember()" for all compliant c++ compilers?
The pointer is valid, however you have to keep in mind that when a virtual function is invoked through a pointer it is always resolved in accordance with the dynamic type of the object used on the left-hand side. This means that when you invoke a virtual function from the constructor, it doesn't matter whether you invoke it directly or whether you invoke it through a pointer. In both cases the call will resolve to the type whose constructor is currently working. That's how virtual functions work, when you invoke them during object construction (or destruction).
Note also that pointers to member functions are generally not attached to specific functions at the point of initalization. If the target function is non-virtual, they one can say that the pointer points to a specific function. However, if the target function is virtual, there's no way to say where the pointer is pointing to. For example, the language specification explicitly states that when you compare (for equality) two pointers that happen to point to virtual functions, the result is unspecified.
"Valid" is a specific term when applied to pointers. Data pointers are valid when they point to an object or NULL; function pointers are valid when they point to a function or NULL, and pointers to members are valid when the point to a member or NULL.
However, from your question about actual output, I can infer that you wanted to ask something else. Let's look at your vmember function - or should I say functions? Obviously there are two function bodies. You could have made only the derived one virtual, so that too confirms that there are really two vmember functions, who both happen to be virtual.
Now, the question becomes whether when taking the address of a member function already chooses the actual function. Your implementations show that they don't, and that this only happens when the pointer is actually dereferenced.
The reason it must work this way is trivial. Taking the address of a member function does not involve an actual object, something that would be needed to resolve the virtual call. Let me show you:
namespace {
void (A::*test)() = &A::vmember;
A a;
B b;
(a.*test)();
(b.*test)();
}
When we initialize test, there is no object of type A or B at all, yet is it possible to take the address of &A::vmember. That same member pointer can then be used with two different objects. What could this produce but "In A::vmember()\n" and "In B::vmember()\n" ?
Read this article for an in-depth discussion of member function pointers and how to use them. This should answer all your questions.
I have found a little explanation on the Old New Thing (a blog by Raymond Chen, sometimes referred to as Microsoft's Chuck Norris).
Of course it says nothing about the compliance, but it explains why:
B b;
b.A::vmember(); // [1]
(b.*&A::vmember)(); // [2]
1 and 2 actually invoke a different function... which is quite surprising, really. It also means that you can't actually prevent the runtime dispatch using a pointer to member function :/
I think no. Pointer to virtual member function is resolved via VMT, so the same way as call to this function would happen. It means that it is not valid, since VMT is populated after constructor finished.
IMO it is implementation defined to take address of a virtual function. This is because virtual functions are implemented using vtables which are compiler implementation specific. Since the vtable is not guaranteed to be complete until the execution of the class ctor is done, a pointer to an entry in such a table (virtual function) may be implementation defined behavior.
There is a somewhat related question that I asked on SO here few months back; which basically says taking address of the virtual function is not specified in the C++ standard.
So, in any case even if it works for you, the solution will not be portable.

Calling base class definition of virtual member function with function pointer

I want to call the base class implementation of a virtual function using a member function pointer.
class Base {
public:
virtual void func() { cout << "base" << endl; }
};
class Derived: public Base {
public:
void func() { cout << "derived" << endl; }
void callFunc()
{
void (Base::*fp)() = &Base::func;
(this->*fp)(); // Derived::func will be called.
// In my application I store the pointer for later use,
// so I can't simply do Base::func().
}
};
In the code above the derived class implementation of func will be called from callFunc. Is there a way I can save a member function pointer that points to Base::func, or will I have to use using in some way?
In my actual application I use boost::bind to create a boost::function object in callFunc which I later use to call func from another part of my program. So if boost::bind or boost::function have some way of getting around this problem that would also help.
When you call a virtual method via a reference or a pointer you will always activate the virtual call mechanism that finds the most derived type.
Your best bet is to add an alternative function that is not virtual.
What you're trying to do unfortunately isn't possible. Pointer-to-member-functions are designed to maintain the virtualness of the function pointed-to.
Your problem is that a member function pointer is not quite the same as a bare function pointer. It actually isn't just a pointer, but a considerably more complex structure, which varies in its details at the level of the compiler implementation. When you invoke it via the syntax (this->*fp)() you are actually calling it on the original object, which causes virtual function dispatch.
One thing that might work is to cast it to a non-method pointer type. This is a little creaky but I think it should work. You still need to pass a Base * but you do it explicitly and the virtual function dispatch is by-passed:
typedef void BasePointer(Base*);
void callFunc()
{
BasePointer fp = (BasePointer *)&Base::func;
fp(this);
}
Update: Ok, no, you can't do it that way. It's illegal, and wouldn't be safe it if it was legal. The C++ FAQ has more on this. But knowing that doesn't solve your problem. The issue is that, pointer-to-object or pointer-to-member if you want to call Base::func through a Base pointer, the object it is pointing must also be a Base. If you can arrange that, then you can use a member function pointer.
Here's another thought, not pretty, but at least workable. Provide a function in Derived, non-virtual, that explicitly calls Base::func. Point to that instead. It won't scale if you need to do this in the general case of lots of different variants of func and callFunc but it will work fine for one method.
Is there any specific reason for doing this via a function pointer?
You should be able to just write:
Base::func();
to call the base class implementation.
In addition to what quark says, a more general remark is that you should use a signal/slot implementation rather than a bare function pointer. Boost has one, there's libsigc and a bunch of others.
What's wrong with this?
(Base(*this).*fp)();
Now if you're satisfied with that, it raises the question of why you're even using a function pointer in the first place. I think some more context might help.