 |
C++Talk.NET C++ language newsgroups
|
| View previous topic :: View next topic |
| Author |
Message |
udaysk Guest
|
Posted: Sun Nov 13, 2005 3:36 pm Post subject: what does signal::T * ptr represent? |
|
|
Hi, I'm trying to maintain some legacy C++ code. There is this
construct in the code (simplified here) that I didn't understand.
What does the static array do? To me it looks like it holds pointers to
interface part of class A? Would you suggest an alternative to this
architecture?
------------
class signal;
template <class T>
class signalDescriptor {
public:
signal T::* ptr;
};
class signal {
public:
virtual void foo( void ) = 0;
};
template <class T>
class signalContainer: public signal {
public:
static signalDescriptor<T> array[];
void foo( void ) {
std::cout << "inside a foo( )" << std::endl;
}
};
class A: public signal {
public:
void foo( void ) {
std::cout << "inside A::foo( )" << std::endl;
}
};
class B: public signalContainer
public:
A a;
};
signalDescriptor<B> signalContainer<B>::array[ ] = {
{ (signal B::* )& B::a }
};
int main( void ) {
signalDescriptor<B> *p = array[0];
// what do do with ptr?
return 0;
}
---------
Thanks in advance.
Uday
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]
|
|
| Back to top |
|
 |
Bob Hairgrove Guest
|
Posted: Sun Nov 13, 2005 10:53 pm Post subject: Re: what does signal::T * ptr represent? |
|
|
On 13 Nov 2005 10:36:30 -0500, "udaysk" <udaya.s.k (AT) gmail (DOT) com> wrote:
| Quote: | Hi, I'm trying to maintain some legacy C++ code. There is this
construct in the code (simplified here) that I didn't understand.
|
I'm not sure you didn't oversimplify it ...
| Quote: | What does the static array do? To me it looks like it holds pointers to
interface part of class A? Would you suggest an alternative to this
architecture?
------------
class signal;
template <class T
class signalDescriptor {
public:
signal T::* ptr;
};
|
ptr is a pointer to member data of T. That member is of type signal.
However, I'm not sure that this is a valid construct because one
cannot create an object of type signal since it is an abstract class:
| Quote: | class signal {
public:
virtual void foo( void ) = 0;
};
template
class signalContainer: public signal {
public:
static signalDescriptor
|
This shouldn't compile...the dimension of the array must be known at
compile time. However, maybe there is a specialization somewhere that
takes care of this? (That is why I think you "oversimplified"
something.)
| Quote: |
void foo( void ) {
std::cout << "inside a foo( )" << std::endl;
}
};
class A: public signal {
public:
void foo( void ) {
std::cout << "inside A::foo( )" << std::endl;
}
};
class B: public signalContainer
public:
A a;
};
signalDescriptor<B> signalContainer<B>::array[ ] = {
{ (signal B::* )& B::a }
};
|
This would be (slightly) more readable as follows:
signalDescriptor<B> signalContainer<B>::array[ ] = {
{ (signal B::* ) &B::a }
};
Note the different placement of the single space at "&B::a".
| Quote: |
int main( void ) {
signalDescriptor<B> *p = array[0];
|
Where is array[] defined? Is this supposed to be an alias for
signalContainer<B>::array?
| Quote: | // what do do with ptr?
return 0;
}
|
After adding the missing includes for <iostream> and <ostream>, I
still get two errors in compilation (using Borland 5.5.1):
signal_desc.cpp:
Error E2426 signal_desc.cpp 40: Explicit specialization of
'signalContainer<B>::array' requires 'template<>' declaration
Error E2451 signal_desc.cpp 46: Undefined symbol 'array' in function
main()
Warning W8004 signal_desc.cpp 51: 'p' is assigned a value that is
never used in function main()
--
Bob Hairgrove
[email]NoSpamPlease (AT) Home (DOT) com[/email]
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]
|
|
| Back to top |
|
 |
Ron Natalie Guest
|
Posted: Mon Nov 14, 2005 12:06 am Post subject: Re: what does signal::T * ptr represent? |
|
|
udaysk wrote:
| Quote: | template <class T
class signalDescriptor {
public:
signal T::* ptr;
};
|
ptr points to a member of class T of type signal.
If we had a class like this:
class C {
public:
signal x;
};
we could initialize the ptr in the class signalDescriptor:
signalDescriptor
sdc.ptr = &C: ;
we can reference it like this:
C c;
c.*sdc.ptr
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]
|
|
| Back to top |
|
 |
Bob Hairgrove Guest
|
Posted: Mon Nov 14, 2005 4:47 pm Post subject: Re: what does signal::T * ptr represent? |
|
|
On 13 Nov 2005 19:06:36 -0500, Ron Natalie <ron (AT) spamcop (DOT) net> wrote:
| Quote: | udaysk wrote:
template <class T
class signalDescriptor {
public:
signal T::* ptr;
};
ptr points to a member of class T of type signal.
If we had a class like this:
class C {
public:
signal x;
};
we could initialize the ptr in the class signalDescriptor:
signalDescriptor
sdc.ptr = &C: ;
we can reference it like this:
C c;
c.*sdc.ptr
|
The rest of the OP's code shows that signal is an abstract base class
which cannot be instantiated as an object. What are the implications
of using such a pointer to member (WRT slicing)? Can a signal T::*
actually point to a derived object?
--
Bob Hairgrove
[email]NoSpamPlease (AT) Home (DOT) com[/email]
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]
|
|
| Back to top |
|
 |
Pete Becker Guest
|
Posted: Tue Nov 15, 2005 9:06 am Post subject: Re: what does signal::T * ptr represent? |
|
|
Bob Hairgrove wrote:
| Quote: |
The rest of the OP's code shows that signal is an abstract base class
which cannot be instantiated as an object. What are the implications
of using such a pointer to member (WRT slicing)?
|
None. A pointer to member points to a member. Doesn't matter whether the
class it's a member of is abstract, polymorphic, or green.
| Quote: | Can a signal T::*
actually point to a derived object?
|
Sorry, I don't know how to parse "derived object" here. In general,
though, a pointer to a member of T can be initialized with the address
of a member of a base of T, but not with the address of a member of a
class derived from T. That's because a member of a type derived from T
is not necessarily a member of T.
Note that pointers to members of a class T exist without regard to
whether there are any objects of type T.
--
Pete Becker
Dinkumware, Ltd. (http://www.dinkumware.com)
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]
|
|
| Back to top |
|
 |
kanze Guest
|
Posted: Tue Nov 15, 2005 2:34 pm Post subject: Re: what does signal::T * ptr represent? |
|
|
Pete Becker wrote:
| Quote: | Bob Hairgrove wrote:
The rest of the OP's code shows that signal is an abstract
base class which cannot be instantiated as an object. What
are the implications of using such a pointer to member (WRT
slicing)?
None. A pointer to member points to a member. Doesn't matter
whether the class it's a member of is abstract, polymorphic,
or green.
Can a signal T::*
actually point to a derived object?
Sorry, I don't know how to parse "derived object" here. In
general, though, a pointer to a member of T can be initialized
with the address of a member of a base of T, but not with the
address of a member of a class derived from T. That's because
a member of a type derived from T is not necessarily a member
of T.
|
That's true, but you can convert a pointer to member of the
derived class to a pointer to member of the base class by means
of a static_cast. Following that, you can use the pointer to
member with a pointer to the base class, provided the actual
dynamic type of the pointed to object is of the derived class.
That is to say, the following is legal:
class Base {} ;
class Derived : public Base { int i ; } ;
int Base::*pmi = static_cast< int Base::* >( &Derived::i ) ;
Base* pd = new Derived ;
pd->*pmi = 42 ;
(At least, that is how I interpret §5.2.9/9 and §5.5/4.)
--
James Kanze GABI Software
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
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]
|
|
| Back to top |
|
 |
Bob Hairgrove Guest
|
Posted: Tue Nov 15, 2005 2:36 pm Post subject: Re: what does signal::T * ptr represent? |
|
|
On 15 Nov 2005 04:06:54 -0500, Pete Becker <petebecker (AT) acm (DOT) org> wrote:
| Quote: | Bob Hairgrove wrote:
The rest of the OP's code shows that signal is an abstract base class
which cannot be instantiated as an object. What are the implications
of using such a pointer to member (WRT slicing)?
None. A pointer to member points to a member. Doesn't matter whether the
class it's a member of is abstract, polymorphic, or green.
|
Well, I suppose it cannot ever actually be used because if the member
is abstract, there cannot be a valid template argument type containing
a member of the abstract type, and you cannot convert a Base T::* to a
Derived T::*, e.g. (...see code further down...)
| Quote: | Can a signal T::*
actually point to a derived object?
Sorry, I don't know how to parse "derived object" here.
|
Yes, I meant "derived member" here. But in order to instantiate such a
template, signal cannot be abstract, as you have just pointed out:
| Quote: | In general, though, a pointer to a member of T can be initialized with the address
of a member of a base of T, but not with the address of a member of a
class derived from T. That's because a member of a type derived from T
is not necessarily a member of T.
Note that pointers to members of a class T exist without regard to
whether there are any objects of type T.
|
They might exist, but they cannot be used in this case, e.g.:
#include <iostream>
#include <ostream>
// Base is abstract:
struct Base {
virtual ~Base() {}
virtual void fun() = 0;
};
struct Derived : public Base {
void fun() { std::cout << "Derived fun" << std::endl; }
};
/* doesn't compile, obviously:
struct HasBase {
Base obj; // because Base is abstract
};
*/
struct HasDerived {
Derived obj;
};
template
class PTM_Holder {
public:
PTM_Holder()
: basePtr(&T::obj) {}
void call_fun(T & hd) { (hd.*basePtr).fun(); }
private:
Base T::* basePtr;
// change "Base" to "Derived" to make
// the error below disappear...
};
int main() {
PTM_Holder<HasDerived> ptm_derived; // ERROR:
// cannot convert 'Derived HasDerived::*'
// to 'Base HasDerived::*' in function
// PTM_Holder<HasDerived>::PTM_Holder()
HasDerived d;
// call fun() through PTM_Holder's pointer to member:
ptm_derived.call_fun(d);
return 0;
}
--
Bob Hairgrove
[email]NoSpamPlease (AT) Home (DOT) com[/email]
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]
|
|
| Back to top |
|
 |
Pete Becker Guest
|
Posted: Tue Nov 15, 2005 3:51 pm Post subject: Re: what does signal::T * ptr represent? |
|
|
kanze wrote:
| Quote: | Pete Becker wrote:
Bob Hairgrove wrote:
The rest of the OP's code shows that signal is an abstract
base class which cannot be instantiated as an object. What
are the implications of using such a pointer to member (WRT
slicing)?
None. A pointer to member points to a member. Doesn't matter
whether the class it's a member of is abstract, polymorphic,
or green.
Can a signal T::*
actually point to a derived object?
Sorry, I don't know how to parse "derived object" here. In
general, though, a pointer to a member of T can be initialized
with the address of a member of a base of T, but not with the
address of a member of a class derived from T. That's because
a member of a type derived from T is not necessarily a member
of T.
That's true, but you can convert a pointer to member of the
derived class to a pointer to member of the base class by means
of a static_cast. Following that, you can use the pointer to
member with a pointer to the base class, provided the actual
dynamic type of the pointed to object is of the derived class.
That is to say, the following is legal:
class Base {} ;
class Derived : public Base { int i ; } ;
int Base::*pmi = static_cast< int Base::* >( &Derived::i ) ;
Base* pd = new Derived ;
pd->*pmi = 42 ;
(At least, that is how I interpret §5.2.9/9 and §5.5/4.)
|
I don't think that applies here: the dynamic type of the object pointed
to by pd is Base, 'cause Base is not a polymorphic type. Granted, that's
not really your point (adding a virtual function to Base would eliminate
this objection), but it does underscore the dangers of playing this kind
of game with pointers to members.
--
Pete Becker
Dinkumware, Ltd. (http://www.dinkumware.com)
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]
|
|
| Back to top |
|
 |
Pete Becker Guest
|
Posted: Wed Nov 16, 2005 12:43 am Post subject: Re: what does signal::T * ptr represent? |
|
|
Bob Hairgrove wrote:
| Quote: |
Well, I suppose it cannot ever actually be used because if the member
is abstract, there cannot be a valid template argument type containing
a member of the abstract type, and you cannot convert a Base T::* to a
Derived T::*, e.g. (...see code further down...)
|
Whoops, sorry: I got tangled up on which is the abstract class. In my
previous message I was talking about T being abstract; that's not the
case here, as you point out.
--
Pete Becker
Dinkumware, Ltd. (http://www.dinkumware.com)
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]
|
|
| Back to top |
|
 |
kanze Guest
|
Posted: Wed Nov 16, 2005 12:50 pm Post subject: Re: what does signal::T * ptr represent? |
|
|
Pete Becker wrote:
| Quote: | kanze wrote:
Pete Becker wrote:
Bob Hairgrove wrote:
The rest of the OP's code shows that signal is an abstract
base class which cannot be instantiated as an object. What
are the implications of using such a pointer to member (WRT
slicing)?
None. A pointer to member points to a member. Doesn't matter
whether the class it's a member of is abstract, polymorphic,
or green.
Can a signal T::*
actually point to a derived object?
Sorry, I don't know how to parse "derived object" here. In
general, though, a pointer to a member of T can be
initialized with the address of a member of a base of T, but
not with the address of a member of a class derived from T.
That's because a member of a type derived from T is not
necessarily a member of T.
That's true, but you can convert a pointer to member of the
derived class to a pointer to member of the base class by
means of a static_cast. Following that, you can use the
pointer to member with a pointer to the base class, provided
the actual dynamic type of the pointed to object is of the
derived class. That is to say, the following is legal:
class Base {} ;
class Derived : public Base { int i ; } ;
int Base::*pmi = static_cast< int Base::* >( &Derived::i ) ;
Base* pd = new Derived ;
pd->*pmi = 42 ;
(At least, that is how I interpret §5.2.9/9 and §5.5/4.)
I don't think that applies here: the dynamic type of the
object pointed to by pd is Base, 'cause Base is not a
polymorphic type. Granted, that's not really your point
(adding a virtual function to Base would eliminate this
objection), but it does underscore the dangers of playing this
kind of game with pointers to members.
|
Intuitively, I would have thought that the dynamic type was
Derived, virtual functions or not. The standard does allow the
compiler to ignore the dynamic type in almost every case where
the object is not polymorphic, of course. But I don't see that
here. And of course, "intuitively" isn't always correct when it
comes to reading the standard.
Which still doesn't mean that it's a safe kind of game to play.
Throw in a virtual inheritance somewhere, and it stops working.
And of course, unless the class is polymorphic, you can't verify
that the dynamic type is correct, so you're playing with fire
anyway. What I don't understand in such cases is why the author
didn't simply put the necessary virtual function in Base, and be
done with it. Simple, robust and understandable beats complex,
fragile and obscure any day. And to top it off, there's a good
chance that calling a virtual function will be faster than
calling through a pointer to member function.
--
James Kanze GABI Software
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
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]
|
|
| Back to top |
|
 |
Pete Becker Guest
|
Posted: Wed Nov 16, 2005 5:56 pm Post subject: Re: what does signal::T * ptr represent? |
|
|
kanze wrote:
| Quote: |
Intuitively, I would have thought that the dynamic type was
Derived, virtual functions or not.
|
Your intuition is right: I remembered wrong. The dynamic type of an
lvalue is the most derived type of the object, and the example given in
the standard is that given a pointer p to type B that points to an
object of type D (where D is derived from B), the dynamic type of *p is D.
--
Pete Becker
Dinkumware, Ltd. (http://www.dinkumware.com)
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]
|
|
| Back to top |
|
 |
|
|
You cannot post new topics in this forum You cannot reply to topics in this forum You cannot edit your posts in this forum You cannot delete your posts in this forum You cannot vote in polls in this forum
|
|