 |
C++Talk.NET C++ language newsgroups
|
| View previous topic :: View next topic |
| Author |
Message |
Hiram Berry Guest
|
Posted: Thu Jun 26, 2003 2:16 pm Post subject: Re: Pointer-to-member-functions and inheritance |
|
|
"Richard Garner" <mohammedalfayed (AT) hotmail (DOT) com> wrote
| Quote: | Hi all,
I have the following setup:
|
[... snipped first approach for brevity ]
| Quote: | Now, this works fine; however, I'd like if at all possible to avoid
the doubly indirect function call in calling Work() on my derived
objects. Therefore I have been wondering about the following
replacement. Unfortunately, I suspect it may not be valid C++ code:
#include <iostream
class Base
{
public:
typedef void (Base::*BaseMemFuncPtr)();
BaseMemFuncPtr ptr;
Base(BaseMemFuncPtr p) : ptr(p) {}
void Work()
{
(this->*ptr)();
}
};
class Derived1 : public Base
{
public:
Derived1(BaseMemFuncPtr p) : Base(p) {}
void D1Choice1() { std::cout << "Function 1" << std::endl; }
void D1Choice2() { std::cout << "Function 2" << std::endl; }
};
|
[...snipped analogous, attempts to call in following manner: ]
| Quote: | d1 = new Derived1(&Derived1::D1Choice1);
d1->Work(); delete d1;
|
Richard,
The only problem is that pointers-to-member convert contravariantly: the
implicit conversion is to _down_ cast, the reverse of how it works with
ordinary pointers to class. You may explicitly upcast them with
static_cast
in calling the ctor, something like:
d1 = new Derived1(static_cast<BaseMemFuncPtr>(&Derived1::D1Choice));
and then the approach should work. The standard down conversion can be
taken advantage of to hide the cast when chaining through a
multiple-level
class hierarchy in client code by an intercalated helper class template,
eg.:
template<class D_type,class B_type=Base> class UpCaster:public B_type{
protected:
typedef void (D_type::*DMemFuncPtr)();
UpCaster(DMemFuncPtr p):B_type(static_cast<BaseMemFuncPtr>(p)){}
};
and slightly edit the derived class definitions, for example:
class Derived1 : public UpCaster<Derived1>
{
public:
Derived1(DMemFuncPtr p) : UpCaster<Derived1>(p) {}
void D1Choice1() { std::cout << "Function 1" << std::endl; }
void D1Choice2() { std::cout << "Function 2" << std::endl; }
};
and to show that it works with serial hierarchy derivation in addition
to
parallel derivation:
class Derived2 : public UpCaster
{
public:
Derived2(DMemFuncPtr p) : UpCaster<Derived2,Derived1>(p) {}
void D2Choice1() { std::cout << "Function 3" << std::endl; }
void D2Choice2() { std::cout << "Function 4" << std::endl; }
};
use it:
Base *d1=new Derived1(&Derived1::D1Choice1);
Base *d2=new Derived2(&Derived2::D2Choice2);
d1->Work();
d2->Work();
| Quote: | Now, MSVC 7.1 baulks at this implicit casting of
pointers-to-derived-class-member-functions to
pointers-to-base-class-member-functions; however Intel 7 merrily
compiles and runs it. I have a feeling that MSVC is the more correct
of the two in this case. Is this true?
Yes.
And if so, is there any other
way of avoiding the double indirection,
I think there are other similar ways. Working this hard to avoid dynamic |
dispatch really doesn't save you much overhead though.
| Quote: | or is it an inescapable
corollary of the C++ object model?
No. |
HTH,
Hiram Berry
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]
|
|
| Back to top |
|
 |
Thomas Richter Guest
|
Posted: Thu Jun 26, 2003 7:32 pm Post subject: Re: Pointer-to-member-functions and inheritance |
|
|
Hi,
/* snip */
| Quote: | class Base
{
public:
typedef void (Base::*BaseMemFuncPtr)();
BaseMemFuncPtr ptr;
Base(BaseMemFuncPtr p) : ptr(p) {}
void Work()
{
(this->*ptr)();
}
};
class Derived1 : public Base
{
public:
Derived1(BaseMemFuncPtr p) : Base(p) {}
void D1Choice1() { std::cout << "Function 1" << std::endl; }
void D1Choice2() { std::cout << "Function 2" << std::endl; }
};
Now, MSVC 7.1 baulks at this implicit casting of
pointers-to-derived-class-member-functions to
pointers-to-base-class-member-functions; however Intel 7 merrily
compiles and runs it. I have a feeling that MSVC is the more correct
of the two in this case. Is this true?
|
IMHO yes, simply because all you know when you call a method thru "p" is
that its implicit "this" pointer points to an object of type "base"
which might or might not have the fields that are accessed in the
methods of the derived object.
| Quote: | And if so, is there any other
way of avoiding the double indirection, or is it an inescapable
corollary of the C++ object model?
|
I would consider to rethink your design. For example, is it really
necessary to use pointers to member functions? In your case, I would
for example put the "Choice" functions as virtual methods into an
intermediate object you derive from. Since you don't seem to call
D1Choice1() directly, but only indirectly thru the base, I would
further make this private. (This is because it is one of my
experiences that people trained in C programming often think in terms
of function pointers where virtual methods would have been the better,
or at least more canonical choice for C++).
Greetings,
Thomas
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]
|
|
| Back to top |
|
 |
Andrey Tarasevich Guest
|
Posted: Thu Jun 26, 2003 7:41 pm Post subject: Re: Pointer-to-member-functions and inheritance |
|
|
Richard Garner wrote:
| Quote: | ...
Now, this works fine; however, I'd like if at all possible to avoid
the doubly indirect function call in calling Work() on my derived
objects. Therefore I have been wondering about the following
replacement. Unfortunately, I suspect it may not be valid C++ code:
#include <iostream
class Base
{
public:
typedef void (Base::*BaseMemFuncPtr)();
BaseMemFuncPtr ptr;
Base(BaseMemFuncPtr p) : ptr(p) {}
void Work()
{
(this->*ptr)();
}
};
class Derived1 : public Base
{
public:
Derived1(BaseMemFuncPtr p) : Base(p) {}
void D1Choice1() { std::cout << "Function 1" << std::endl; }
void D1Choice2() { std::cout << "Function 2" << std::endl; }
};
class Derived2 : public Base
{
public:
Derived2(BaseMemFuncPtr p) : Base(p) {}
void D2Choice1() { std::cout << "Function 3" << std::endl; }
void D2Choice2() { std::cout << "Function 4" << std::endl; }
};
int main()
{
Base *d1, *d2, *d3, *d4;
d1 = new Derived1(&Derived1::D1Choice1);
d2 = new Derived1(&Derived1::D1Choice2);
d3 = new Derived2(&Derived2::D2Choice1);
d4 = new Derived2(&Derived2::D2Choice2);
d1->Work(); delete d1;
d2->Work(); delete d2;
d3->Work(); delete d3;
d4->Work(); delete d4;
}
Now, MSVC 7.1 baulks at this implicit casting of
pointers-to-derived-class-member-functions to
pointers-to-base-class-member-functions; however Intel 7 merrily
compiles and runs it.
|
MSVC 7 is right. This conversion is not a standard conversion and , for
this reason, it cannot be performed implicitly. However, it can be
performed explicitly by using 'static_cast'. The resultant code is
perfectly legal and will work as expected.
| Quote: | I have a feeling that MSVC is the more correct
of the two in this case. Is this true?
|
Yes.
| Quote: | And if so, is there any other
way of avoiding the double indirection, or is it an inescapable
corollary of the C++ object model?
|
Just use an explicit 'static_cast' in order to convert a
pointer-to-member-of-derived-class to a pointer-to-member-of-base-class.
You can do it in the derived class' constructors:
class Derived1 : public Base
{
public:
typedef void (Derived1::*DerivedMemFuncPtr)();
Derived1(DerivedMemFuncPtr p) :
Base(static_Cast<BaseMemFuncPtr>(p))
{}
...
--
Best regards,
Andrey Tarasevich
Brainbench C and C++ Programming MVP
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]
|
|
| Back to top |
|
 |
nick@byu.edu Guest
|
Posted: Thu Jun 26, 2003 10:28 pm Post subject: Re: Pointer-to-member-functions and inheritance |
|
|
Can you not just split D1 and D2 each into two different classes?
You're essentially reimplementing C++'s run-time polymorphism mechanism...so
why not use what's already built-in?
[ 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
|
|