473,387 Members | 1,876 Online
Bytes | Software Development & Data Engineering Community
Post Job

Home Posts Topics Members FAQ

Join Bytes to post your question to a community of 473,387 software developers and data experts.

Pointers to Members question

Hi,

Is this code okay and compliant with the standard. As far as I
understand it is correct but I just want to make sure.

Thank you,
Ben.

----

#include <iostream>
using namespace std;

class Base {
public:
typedef void (Base::*PMethod)(void);
void Invoke (PMethod p) {(this->*p)();}
};

class Derived : public Base {
public:
void Method (void) {cout << "Hello World" << endl;}
};

int main (void) {
Derived x;
// *** Is the static_cast correct here ? Or could this leads
// to undefined behavior on some platform / compiler ?
x.Invoke(static_cast<Base::PMethod>(&Derived::Meth od));
return 0;
}
Sep 21 '07 #1
6 1210
Ben Thomas wrote:
Hi,

Is this code okay and compliant with the standard. As far as I
understand it is correct but I just want to make sure.

Thank you,
Ben.

----

#include <iostream>
using namespace std;

class Base {
public:
typedef void (Base::*PMethod)(void);
void Invoke (PMethod p) {(this->*p)();}
};

class Derived : public Base {
public:
void Method (void) {cout << "Hello World" << endl;}
};

int main (void) {
Derived x;
// *** Is the static_cast correct here ? Or could this leads
// to undefined behavior on some platform / compiler ?
x.Invoke(static_cast<Base::PMethod>(&Derived::Meth od));
return 0;
}
Generally speaking, a member of derived is NOT a member of base,
and that's why the conversion does not exist, and you have to resort
to some tricks (like casts) to silence the compiler that complains
otherwise. The static cast (as I understand it) would be called for
if you have a pointer to member of 'Base' ('Base::*ptr'), somehow
it was converted to a pointer to a member of 'Derived' ('Derived::*')
and then your base wants to call it. Then, since _originally_ the
pointer *was* to a member of 'Base', you're ok to use 'static_cast'.
If the pointer *never was* to a member of 'Base', casting is *not*
the right thing to do. You're correct suspecting that the behaviour
is undefined.

V
--
Please remove capital 'A's when replying by e-mail
I do not respond to top-posted replies, please don't ask
Sep 21 '07 #2
On 2007-09-21 16:36:43 -0400, "Victor Bazarov" <v.********@comAcast.netsaid:
>
The static cast (as I understand it) would be called for
if you have a pointer to member of 'Base' ('Base::*ptr'), somehow
it was converted to a pointer to a member of 'Derived' ('Derived::*')
and then your base wants to call it. Then, since _originally_ the
pointer *was* to a member of 'Base', you're ok to use 'static_cast'.
If the pointer *never was* to a member of 'Base', casting is *not*
the right thing to do. You're correct suspecting that the behaviour
is undefined.
More generally, once you cast it, you have to cast it back to its
original type to get well-defined behavior.

--
Pete
Roundhouse Consulting, Ltd. (www.versatilecoding.com) Author of "The
Standard C++ Library Extensions: a Tutorial and Reference
(www.petebecker.com/tr1book)

Sep 21 '07 #3
On Sep 21, 10:36 pm, "Victor Bazarov" <v.Abaza...@comAcast.netwrote:
Ben Thomas wrote:
Is this code okay and compliant with the standard. As far as I
understand it is correct but I just want to make sure.
#include <iostream>
using namespace std;
class Base {
public:
typedef void (Base::*PMethod)(void);
void Invoke (PMethod p) {(this->*p)();}
};
class Derived : public Base {
public:
void Method (void) {cout << "Hello World" << endl;}
};
int main (void) {
Derived x;
// *** Is the static_cast correct here ? Or could this leads
// to undefined behavior on some platform / compiler ?
x.Invoke(static_cast<Base::PMethod>(&Derived::Meth od));
return 0;
}
Generally speaking, a member of derived is NOT a member of base,
and that's why the conversion does not exist, and you have to resort
to some tricks (like casts) to silence the compiler that complains
otherwise. The static cast (as I understand it) would be called for
if you have a pointer to member of 'Base' ('Base::*ptr'), somehow
it was converted to a pointer to a member of 'Derived' ('Derived::*')
and then your base wants to call it. Then, since _originally_ the
pointer *was* to a member of 'Base', you're ok to use 'static_cast'.
If the pointer *never was* to a member of 'Base', casting is *not*
the right thing to do. You're correct suspecting that the behaviour
is undefined.
I think you've got it backwards. Pointer to member casts work
the opposite of normal pointer casts. There is an implicit D::*
to B::* conversion (no cast needed). A static_cast is needed
for D::* to B::*, however, and the using it is only legal if the
B it is used with is actually a D. Which is the case above. So
while the above may be as ugly as sin, it is perfectly legal
(and was used for callbacks in one GUI library---XViews, I
think---that was widely used in the past).

--
James Kanze (GABI Software) email:ja*********@gmail.com
Conseils en informatique orientée objet/
Beratung in objektorientierter Datenverarbeitung
9 place Sémard, 78210 St.-Cyr-l'École, France, +33 (0)1 30 23 00 34

Sep 23 '07 #4
James Kanze wrote:
On Sep 21, 10:36 pm, "Victor Bazarov" <v.Abaza...@comAcast.netwrote:
>Ben Thomas wrote:
>>Is this code okay and compliant with the standard. As far as I
understand it is correct but I just want to make sure.
>>#include <iostream>
using namespace std;
>>class Base {
public:
typedef void (Base::*PMethod)(void);
void Invoke (PMethod p) {(this->*p)();}
};
>>class Derived : public Base {
public:
void Method (void) {cout << "Hello World" << endl;}
};
>>int main (void) {
Derived x;
// *** Is the static_cast correct here ? Or could this leads
// to undefined behavior on some platform / compiler ?
x.Invoke(static_cast<Base::PMethod>(&Derived::Meth od));
return 0;
}
>Generally speaking, a member of derived is NOT a member of base,
and that's why the conversion does not exist, and you have to resort
to some tricks (like casts) to silence the compiler that complains
otherwise. The static cast (as I understand it) would be called for
if you have a pointer to member of 'Base' ('Base::*ptr'), somehow
it was converted to a pointer to a member of 'Derived' ('Derived::*')
and then your base wants to call it. Then, since _originally_ the
pointer *was* to a member of 'Base', you're ok to use 'static_cast'.
If the pointer *never was* to a member of 'Base', casting is *not*
the right thing to do. You're correct suspecting that the behaviour
is undefined.

I think you've got it backwards. Pointer to member casts work
the opposite of normal pointer casts. There is an implicit D::*
to B::* conversion (no cast needed).
Nope. *You* got it backwards. Every member of 'B' is a member of
'D' as well (by inheritance), so 'B::*' =='D::*' requires no special
syntax, its implicit (modulo all the "available" and "unambiguous"
cruft). [conv.mem]/2.

For the pointers to *objects*, however, it's reverse: Every 'D' is
a 'B' (modulo "available" and "unambiguous"), so conversion from 'D*'
to 'B*' is implicit.
A static_cast is needed
for D::* to B::*, however, and the using it is only legal if the
B it is used with is actually a D. Which is the case above. So
while the above may be as ugly as sin, it is perfectly legal
(and was used for callbacks in one GUI library---XViews, I
think---that was widely used in the past).
V
--
Please remove capital 'A's when replying by e-mail
I do not respond to top-posted replies, please don't ask
Sep 24 '07 #5
On Sep 24, 3:59 pm, "Victor Bazarov" <v.Abaza...@comAcast.netwrote:
James Kanze wrote:
On Sep 21, 10:36 pm, "Victor Bazarov" <v.Abaza...@comAcast.netwrote:
[...]
Generally speaking, a member of derived is NOT a member of base,
and that's why the conversion does not exist, and you have to resort
to some tricks (like casts) to silence the compiler that complains
otherwise. The static cast (as I understand it) would be called for
if you have a pointer to member of 'Base' ('Base::*ptr'), somehow
it was converted to a pointer to a member of 'Derived' ('Derived::*')
and then your base wants to call it. Then, since _originally_ the
pointer *was* to a member of 'Base', you're ok to use 'static_cast'.
If the pointer *never was* to a member of 'Base', casting is *not*
the right thing to do. You're correct suspecting that the behaviour
is undefined.
I think you've got it backwards. Pointer to member casts work
the opposite of normal pointer casts. There is an implicit D::*
to B::* conversion (no cast needed).
Nope. *You* got it backwards. Every member of 'B' is a member of
'D' as well (by inheritance), so 'B::*' =='D::*' requires no special
syntax, its implicit (modulo all the "available" and "unambiguous"
cruft). [conv.mem]/2.
For the pointers to *objects*, however, it's reverse: Every 'D' is
a 'B' (modulo "available" and "unambiguous"), so conversion from 'D*'
to 'B*' is implicit.
Yes. There's a mix of misunderstanding what you wrote, and
mistyping what I wanted to say, there. What I wanted to say was
that the implicit conversions go in the opposite sense for
pointers to members, compared to pointers to objects (which you
just said in a lot clearer form), but that just like pointers to
objects, you can static_cast in the opposite sense of the
implicit conversion, *provided* the actual type is really a
derived; i.e. Base* -Derived* is legal if the object pointed
to by Base* is actually a Derived, and Derived::* to Base::* is
legal if the resulting pointer to member is only used with the
address of a Base which is actually a Derived.

So you were wrong concerning undefined behavior. But to be
quite frank, I also thought it was undefined until I ran into a
large code base which used it.

--
James Kanze (GABI Software) email:ja*********@gmail.com
Conseils en informatique orientée objet/
Beratung in objektorientierter Datenverarbeitung
9 place Sémard, 78210 St.-Cyr-l'École, France, +33 (0)1 30 23 00 34

Sep 25 '07 #6
On Sep 21, 11:22 pm, Pete Becker <p...@versatilecoding.comwrote:
On 2007-09-21 16:36:43 -0400, "Victor Bazarov" <v.Abaza...@comAcast.netsaid:
The static cast (as I understand it) would be called for
if you have a pointer to member of 'Base' ('Base::*ptr'), somehow
it was converted to a pointer to a member of 'Derived' ('Derived::*')
and then your base wants to call it. Then, since _originally_ the
pointer *was* to a member of 'Base', you're ok to use 'static_cast'.
If the pointer *never was* to a member of 'Base', casting is *not*
the right thing to do. You're correct suspecting that the behaviour
is undefined.
More generally, once you cast it, you have to cast it back to its
original type to get well-defined behavior.
Not really. Consider:

struct Base
{
virtual ~Base() {}
} ;

struct Derived1 : public Base
{
int i ;
} ;

struct Derived2 : public Base
{
double d ;
} ;

int Base::* pmi = static_cast< int Base::* >( &Derived1::i ) ;
Base* pd1 = new Derived1 ;
Base* pd2 = new Derived2 ;
pd1->*pmi = 42 ; // legal and well defined
pd2->*pmi = 42 ; // undefined behavior.

--
James Kanze (GABI Software) email:ja*********@gmail.com
Conseils en informatique orientée objet/
Beratung in objektorientierter Datenverarbeitung
9 place Sémard, 78210 St.-Cyr-l'École, France, +33 (0)1 30 23 00 34

Sep 25 '07 #7

This thread has been closed and replies have been disabled. Please start a new discussion.

Similar topics

19
by: Thomas Matthews | last post by:
Hi, Given a structure of pointers: struct Example_Struct { unsigned char * ptr_buffer; unsigned int * ptr_numbers; }; And a function that will accept the structure:
3
by: ozbear | last post by:
This is probably an obvious question. I know that pointer comparisons are only defined if the two pointers point somewhere "into" the storage allocated to the same object, or if they are NULL,...
13
by: brian | last post by:
Quick question: if I have a structure: struct foo { unsigned char *packet; unsigned char *ip_src; };
47
by: sunglo | last post by:
Some time a go, in a discussion here in comp.lang.c, I learnt that it's better not to use a (sometype **) where a (void **) is expected (using a cast). Part of the discussion boiled down to the...
3
by: andy_dufresne | last post by:
have posted the question here: http://groups.google.com/group/programpara/browse_thread/thread/75b58c897f890930
20
by: Joe Van Dyk | last post by:
Is there some rule of thumb about when to use pointers to an object and when to use a reference* to an object when a class needs to have objects as data members? Example: class A { B* b_ptr;...
18
by: chankl | last post by:
Can anyone explain what's an opaque pointer and how it's implemented in C? I read about this concept in the book "C interfaces and implementations". Here's an example from the book (list.h -...
66
by: Praveen | last post by:
Hi, I came across a program as follows main() { int x, y ; int *p1 = &x; int *p2 = &y; printf("%d\n", p1-p2); }
25
by: J Caesar | last post by:
In C you can compare two pointers, p<q, as long as they come from the same array or the same malloc()ated block. Otherwise you can't. What I'd like to do is write a function int comparable(void...
0
by: aa123db | last post by:
Variable and constants Use var or let for variables and const fror constants. Var foo ='bar'; Let foo ='bar';const baz ='bar'; Functions function $name$ ($parameters$) { } ...
0
by: emmanuelkatto | last post by:
Hi All, I am Emmanuel katto from Uganda. I want to ask what challenges you've faced while migrating a website to cloud. Please let me know. Thanks! Emmanuel
0
BarryA
by: BarryA | last post by:
What are the essential steps and strategies outlined in the Data Structures and Algorithms (DSA) roadmap for aspiring data scientists? How can individuals effectively utilize this roadmap to progress...
1
by: Sonnysonu | last post by:
This is the data of csv file 1 2 3 1 2 3 1 2 3 1 2 3 2 3 2 3 3 the lengths should be different i have to store the data by column-wise with in the specific length. suppose the i have to...
0
by: Hystou | last post by:
There are some requirements for setting up RAID: 1. The motherboard and BIOS support RAID configuration. 2. The motherboard has 2 or more available SATA protocol SSD/HDD slots (including MSATA, M.2...
0
marktang
by: marktang | last post by:
ONU (Optical Network Unit) is one of the key components for providing high-speed Internet services. Its primary function is to act as an endpoint device located at the user's premises. However,...
0
by: Hystou | last post by:
Most computers default to English, but sometimes we require a different language, especially when relocating. Forgot to request a specific language before your computer shipped? No problem! You can...
0
Oralloy
by: Oralloy | last post by:
Hello folks, I am unable to find appropriate documentation on the type promotion of bit-fields when using the generalised comparison operator "<=>". The problem is that using the GNU compilers,...
0
jinu1996
by: jinu1996 | last post by:
In today's digital age, having a compelling online presence is paramount for businesses aiming to thrive in a competitive landscape. At the heart of this digital strategy lies an intricately woven...

By using Bytes.com and it's services, you agree to our Privacy Policy and Terms of Use.

To disable or enable advertisements and analytics tracking please visit the manage ads & tracking page.