Programming This forum is for all programming questions.
The question does not have to be directly related to Linux and any language is fair game. |
Notices |
Welcome to LinuxQuestions.org, a friendly and active Linux Community.
You are currently viewing LQ as a guest. By joining our community you will have the ability to post topics, receive our newsletter, use the advanced search, subscribe to threads and access many other special features. Registration is quick, simple and absolutely free. Join our community today!
Note that registered members see fewer ads, and ContentLink is completely disabled once you log in.
Are you new to LinuxQuestions.org? Visit the following links:
Site Howto |
Site FAQ |
Sitemap |
Register Now
If you have any problems with the registration process or your account login, please contact us. If you need to reset your password, click here.
Having a problem logging in? Please visit this page to clear all LQ-related cookies.
Get a virtual cloud desktop with the Linux distro that you want in less than five minutes with Shells! With over 10 pre-installed distros to choose from, the worry-free installation life is here! Whether you are a digital nomad or just looking for flexibility, Shells can put your Linux machine on the device that you want to use.
Exclusive for LQ members, get up to 45% off per month. Click here for more info.
|
 |
|
03-04-2011, 11:05 PM
|
#1
|
Senior Member
Registered: Dec 2008
Posts: 4,732
|
C++: callbacks
I am unable to understand the highlighted code/syntax here 
and what do variable names starting with an underscore represent?
Code:
#include <iostream>
template <class Class, typename ReturnType, typename Parameter>
class SingularCallBack
{
public:
typedef ReturnType (Class :: *Method)(Parameter);
SingularCallBack (Class *_class_instance, Method _method)
{
class_instance = _class_instance;
method = _method;
};
ReturnType execute (Parameter parameter)
{
return (class_instance->*method)(parameter);
};
private:
Class *class_instance;
Method method;
};
class A
{
public:
void output()
{
std :: cout << "I am class A :D\n";
};
};
class B
{
public:
bool methodB (A a)
{
a.output();
return true;
}
};
int main ()
{
A a;
B b;
SingularCallBack <B, bool, A> *cb;
cb = new SingularCallBack <B, bool, A> (&b, &B :: methodB);
if (cb->execute (a))
{
std::cout << "CallBack Fired Successfully!" << std::endl;
}
else
{
std::cout << "CallBack Fired Unsuccessfully!" << std::endl;
}
return 0;
}
Last edited by Aquarius_Girl; 03-05-2011 at 01:13 AM.
|
|
|
Click here to see the post LQ members have rated as the most helpful post in this thread.
|
03-05-2011, 02:31 AM
|
#2
|
Senior Member
Registered: Mar 2004
Location: england
Distribution: Mint, Armbian, NetBSD, Puppy, Raspbian
Posts: 3,516
|
does this help?
http://www.parashift.com/c++-faq-lit....html#faq-33.1
cplusplus.com is good too.
variables/functions with starting underscores are a convention in libraries and implementations to
prevent namespace clashes, look in some header files.
typically they denote internal stuff.
In this case the coder is differentiating the parameter from the
data member.
by convention in userland one should not use them.
if you do, people will dissapprove, though it's only convention.
in short they have no meaning to C++, only humans
Last edited by bigearsbilly; 03-05-2011 at 03:03 AM.
|
|
2 members found this post helpful.
|
03-05-2011, 03:25 AM
|
#3
|
Senior Member
Registered: Dec 2008
Posts: 4,732
Original Poster
|
Billy,
That was very helpful, thanks for taking your time.
|
|
|
03-05-2011, 03:30 AM
|
#4
|
Senior Member
Registered: Mar 2004
Location: england
Distribution: Mint, Armbian, NetBSD, Puppy, Raspbian
Posts: 3,516
|
also, I'm a bit rusty but, generally
initialisation lists are preferred over assignment in constructors:
Code:
SingularCallBack (Class * const _class_instance, Method _method):
class_instance(class_instance),
method(_method)
{
//class_instance = _class_instance;
//method = _method;
}
http://www.parashift.com/c++-faq-lit....html#faq-10.6
|
|
1 members found this post helpful.
|
03-05-2011, 05:09 AM
|
#5
|
Senior Member
Registered: Dec 2008
Posts: 4,732
Original Poster
|
Again a helpful pointer, thanks Billy for being around and that site is worth bookmarking!
Last edited by Aquarius_Girl; 03-05-2011 at 05:42 AM.
|
|
|
03-05-2011, 05:13 AM
|
#6
|
Senior Member
Registered: Dec 2008
Posts: 4,732
Original Poster
|
In the below code, the highlighted syntax means that functionName is a function of a class and method is the "object" of the function, functionName??? Please clarify.
Code:
template <class dummyClass, typename ReturnType, typename Parameter>
class SingularCallBack
{
public:
typedef ReturnType (dummyClass :: *functionName)(Parameter);
SingularCallBack (dummyClass *_class_instance, functionName _method)
{
class_instance = _class_instance;
method = _method;
};
ReturnType execute (Parameter parameter)
{
return (class_instance->*method)(parameter);
};
private:
dummyClass *class_instance;
functionName method;
};
|
|
|
03-05-2011, 06:04 AM
|
#7
|
LQ Guru
Registered: Dec 2007
Distribution: Centos
Posts: 5,286
|
In that typedef, functionName is the type being defined.
ReturnType, dummyClass, and Parameter are all types used to define functionName.
If you don't yet understand the way "pointer to member functions" work in C++, you should read some tutorial on that topic. I did a quick google search, and at first glance, the best looking tutorial I saw was
http://www.goingware.com/tips/member-pointers.html
But I haven't reviewed it carefully, so it might not be as good as it looked at first glance. If you don't like that one, redo the google search and try another.
For your example, you also would need to understand the basics of templated class definition. But you probably already understand that, and even if you didn't you should learn the "pointer to member function" syntax and meaning first in order to understand your example.
Edit: I just noticed your other thread on this same topic seems to imply more understanding of "pointer to member" and less understanding of templating. So I don't have a good estimate of what you know vs. what you want explained.
http://www.linuxquestions.org/questi...3/#post4279696
In that thread, you asked how to avoid the typedef. I think that is a foolish thing to even want to do. The code would be far uglier and less readable without the typedef.
But if you really wanted to dump the typedef, you could do that in the same way one would dump any typedef. Use the full (ugly) type specification in each place that the code now uses the typedef.
Regarding your templating confusion in the other thread:
Code:
template <class MyDummyClass, typename (MyDummyClass ::*Method)(Parameter), typename Parameter>
I don't think anything like that is possible in C++. You must put simple names for deduced types in that list and then represent their association into compound types within the body of the definition.
Last edited by johnsfine; 03-05-2011 at 06:23 AM.
|
|
|
03-05-2011, 06:08 AM
|
#8
|
Senior Member
Registered: Dec 2008
Posts: 4,732
Original Poster
|
but you didn't comment on the second highlighted thing, that was my major concern.
|
|
|
03-05-2011, 06:25 AM
|
#9
|
LQ Guru
Registered: Dec 2007
Distribution: Centos
Posts: 5,286
|
Quote:
Originally Posted by Anisha Kaul
but you didn't comment on the second highlighted thing, that was my major concern.
|
I have a habit of posting unfinished answers then hitting edit a few times to finish. That has saved me from loosing too much in many network failures, etc. But it has the drawback as you saw this time that someone sees the unfinished answer and thinks that was all I wrote.
So please reread the above answer. But there wasn't much to say about that highlighted code other than it is wrong.
Edit: Looking at three different posts you wrote with highlighted things, maybe I misunderstand what you mean by "second".
If you mean
Code:
(class_instance->*method)(parameter)
My comment on that was implied within my suggestion to read a tutorial on "pointer to member". Such tutorial would include all three strange syntaxes associated with pointer to member.
The pointer declaration, such as
(Class :: *Method)(Parameter)
The pointer value, such as
&B :: methodB
The use of the pointer, such as
(class_instance->*method)(parameter)
Last edited by johnsfine; 03-05-2011 at 06:42 AM.
|
|
|
03-05-2011, 10:47 AM
|
#10
|
LQ Newbie
Registered: Jul 2004
Location: Portland, OR
Posts: 15
Rep:
|
|
|
|
03-05-2011, 11:47 AM
|
#11
|
Senior Member
Registered: May 2005
Posts: 4,481
|
Quote:
Originally Posted by bigearsbilly
also, I'm a bit rusty but, generally
initialisation lists are preferred over assignment in constructors:
Code:
SingularCallBack (Class * const _class_instance, Method _method):
class_instance(class_instance),
method(_method)
{
//class_instance = _class_instance;
//method = _method;
}
http://www.parashift.com/c++-faq-lit....html#faq-10.6
|
I think there is a typo - an underscore is missing, it should be
Code:
class_instance(_class_instance),
.
|
|
|
03-06-2011, 10:13 PM
|
#12
|
Senior Member
Registered: Dec 2008
Posts: 4,732
Original Poster
|
I will shortly address John's post, meanwhile I have got new problem here:
In the following code, the const std::string& str is what I am not able to understand. This code results in a compilation error, which I solved by removing the above highlighted &.
also, when I remove the base class's & and kept intact the derived class's &, the code compiled but didn't produce any output!
(Scroll down the code tags to see the red highlights)
This doesn't produce any errors when I remove the callback parts and keep the program
simple (i.e including base and the derived classes with the & as a parameter).
Please explain.
Code:
#include <iostream>
#include <vector>
using namespace std;
template <class MyDummyClass, typename ReturnType, typename Parameter>
class SingularCallBack
{
public:
typedef ReturnType (MyDummyClass ::*Method)(Parameter);
SingularCallBack(MyDummyClass* _class_instance, Method _method)
{
class_instance = _class_instance;
method = _method;
};
ReturnType execute(Parameter parameter)
{
return (class_instance->*method)(parameter);
};
private:
MyDummyClass *class_instance;
Method method;
};
class BaseClass
{
public:
BaseClass () {}
virtual bool DerivedMethod (const std::string& str)
{
return true;
}
};
class AClass : public BaseClass
{
public:
AClass () {}
bool DerivedMethod( const std::string& str)
{
std::cout << "Derived Method AClass: " << str << std::endl;
return true;
}
};
int main()
{
std::vector < SingularCallBack < BaseClass, bool, std::string > > callback_list;
AClass a;
callback_list.push_back (SingularCallBack < BaseClass, bool, std::string > (&a, &BaseClass :: DerivedMethod));
for (unsigned int i = 0; i < callback_list.size(); ++i)
{
callback_list[i].execute("abc");
}
return 0;
}
Compilation error:
Code:
anisha@linux-uitj:~> g++ reference.cpp -Wall -Wextra
reference.cpp:32: warning: unused parameter ‘str’
reference.cpp: In function ‘int main()’:
reference.cpp:56: error: no matching function for call to ‘SingularCallBack<BaseClass, bool, std::basic_string<char, std::char_traits<char>, std::allocator<char> > >::SingularCallBack(AClass*, bool (BaseClass::*)(const std::string&))’
reference.cpp:11: note: candidates are: SingularCallBack<MyDummyClass, ReturnType, Parameter>::SingularCallBack(MyDummyClass*, ReturnType (MyDummyClass::*)(Parameter)) [with MyDummyClass = BaseClass, ReturnType = bool, Parameter = std::basic_string<char, std::char_traits<char>, std::allocator<char> >]
reference.cpp:7: note: SingularCallBack<BaseClass, bool, std::basic_string<char, std::char_traits<char>, std::allocator<char> > >::SingularCallBack(const SingularCallBack<BaseClass, bool, std::basic_string<char, std::char_traits<char>, std::allocator<char> > >&)
anisha@linux-uitj:~>
Last edited by Aquarius_Girl; 03-06-2011 at 10:15 PM.
|
|
|
03-07-2011, 01:12 AM
|
#13
|
Senior Member
Registered: Dec 2008
Posts: 4,732
Original Poster
|
Another question:
Template classes like above can be inherited, in which cases does it make sense to inherit them? In our software, we have a base class so on what basis should I decide whether I should
club this class with that one or I should create a new template class?
|
|
|
03-07-2011, 04:17 AM
|
#14
|
Senior Member
Registered: Jun 2006
Location: Maryland
Distribution: Kubuntu, Fedora, RHEL
Posts: 1,541
|
EDIT: Nevermind.
Last edited by dwhitney67; 03-07-2011 at 06:58 AM.
|
|
|
03-07-2011, 06:48 AM
|
#15
|
LQ Guru
Registered: Dec 2007
Distribution: Centos
Posts: 5,286
|
Quote:
Originally Posted by Anisha Kaul
Please explain.
Code:
...
virtual bool DerivedMethod (const std::string& str)
...
std::vector < SingularCallBack < BaseClass, bool, std::string > > callback_list;
...
callback_list.push_back (SingularCallBack < BaseClass, bool, std::string > (&a, &BaseClass :: DerivedMethod));
Compilation error:
|
The compilation error meant exactly what it said. The parameter you used for DerivedMethod (std::string) did not match any parameter you declared for DerivedMethod. You only declared const std::string&
If you change those two lines
Code:
std::vector < SingularCallBack < BaseClass, bool, const std::string& > > callback_list;
...
callback_list.push_back (SingularCallBack < BaseClass, bool, const std::string& > (&a, &BaseClass :: DerivedMethod));
then it compiles.
I'm sure you're used to the fact that you can normally pass a value when a & is expected and you can normally pass a non const when a const is expected. So it is confusing that in this case you can't.
I don't know C++ well enough myself to give you a good explanation of that obscure detail. Sometimes you just need to fix what the compiler objects to even if you're not comfortable with why it objects.
Quote:
also, when I remove the base class's & and kept intact the derived class's &, the code compiled but didn't produce any output!
|
I'm used to getting a compiler warning for that mistake. But I haven't tested to see why you don't get it in this case. The derived class's function has a different signature than the base class's virtual function, so the derived function masks the base function rather than overriding it.
That means the base function is out of scope within the derived function. But you used &BaseClass::DerivedMethod with the derived object, so you overrode the scope to get the base class vtable entry, which points to only the base class method (because you didn't override the method).
A related tricky topic is buried in the meaning of
BaseClass::DerivedMethod
when used in the context of a derived object.
If you were to call BaseClass::DerivedMethod in the derived scope, the BaseClass:: both gets past the problem that the method has been masked out of the current scope and makes the call non virtual, so the BaseClass method is called regardless of whether that function has been overridden for the current object type.
But when you use &BaseClass::DerivedMethod that does not take the address of the above function. Instead it creates a stub function that transfers control through the vtable to the virtual function. In that case, BaseClass:: gets past the problem that the method has been masked out of the current scope and makes the address a pointer to member function rather than an ordinary pointer to function, but it does not stop the actual call from being virtual.
That strange difference between BaseClass::DerivedMethod and &BaseClass::DerivedMethod has confused a lot of C++ programmers.
Last edited by johnsfine; 03-07-2011 at 07:27 AM.
|
|
|
All times are GMT -5. The time now is 05:22 PM.
|
LinuxQuestions.org is looking for people interested in writing
Editorials, Articles, Reviews, and more. If you'd like to contribute
content, let us know.
|
Latest Threads
LQ News
|
|