473,324 Members | 2,356 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,324 software developers and data experts.

accessing subclass members via a base pointer?

Me
I need to be able to acces non-virtual members of sublcasses via a
base class pointer...and without the need for an explicit type cast.
I thought a pure virtual getPtr() that acts as a type cast would solve
the problem, but it appears not to.

I need this functionality to make object serialization a reality. Having
to explicitly cast each deserialized object to its original type defeats
the purpose of my serializing the blasted things in the first place. The
serialization functions all work at this point but the deserialized object,
accessible via a base class pointer, must allow for an "implicit" cast to
the correct subclass. See below...
#include <iostream>
#include <iomanip>

struct base {
virtual base* getPtr()=0;
};
struct subclass: public base {
subclass* getPtr() { return this; }
const char* isA() { return "subclass"; }
};

using namespace std;
int main(int argc, char** argv) {
base* p=new subclass();

// $ g++ test.cc # using gcc 4.1.2 and glibc 2.5.18
// test.cc: In function 'int main()':
// test.cc:19: error: 'struct base' has no member named 'classname'
cout << p->getPtr()->isA() << endl;

return 0;
};

I would EXPECT p->getPtr() to do a correct type cast of the pointer so
that ->isA() is called with a pointer of the correct type, but that's not
happening...WTF!?

Oct 31 '07 #1
6 4554
On Oct 30, 4:59 pm, Me <no...@all.comwrote:
I need to be able to acces non-virtual members of sublcasses via a
base class pointer...and without the need for an explicit type cast.
I thought a pure virtual getPtr() that acts as a type cast would solve
the problem, but it appears not to.

I need this functionality to make object serialization a reality.
I think you're stuck. Why not make a virtual SerializeIt() method
instead?

See below for details
#include <iostream>
#include <iomanip>

struct base {
virtual base* getPtr()=0;};

struct subclass: public base {
subclass* getPtr() { return this; }
const char* isA() { return "subclass"; }

};
getPtr() is not virtual so it is statically bound based on the type,
which is known at compile time.
using namespace std;
int main(int argc, char** argv) {
base* p=new subclass();

p has type "pointer to base"
cout << p->getPtr()->isA() << endl;
Since p is a "base" and getPtr() is not virtual, I would expect the
compiler to generate a call to base::getPtr(). Since base doesn't
have an isA() method in this code, I'd expect it to fail. Does it
actually compile, or does your real code have a base::isA() method?
return 0;

};

I would EXPECT p->getPtr() to do a correct type cast of the pointer so
that ->isA() is called with a pointer of the correct type, but that's not
happening...WTF!
Oct 31 '07 #2
On Wed, 31 Oct 2007 05:11:31 +0000, Tim H wrote:
>
I think you're stuck. Why not make a virtual SerializeIt() method
instead?
Serialization is not a problem and that part works. The problem is
that deserialization is pretty much useless if I still have to do
an explicit cast from a base pointer type back to the correct
subclass in the heirarchy upon object reconstruction.
>struct base {
virtual base* getPtr()=0;};

struct subclass: public base {
subclass* getPtr() { return this; }
const char* isA() { return "subclass"; }

};

getPtr() is not virtual so it is statically bound based on the type,
which is known at compile time.
If you look closely you will see that getPtr() is declared virtual in the
base class and the correct sublcass::getPtr() is being called. I verified
this by inserting an exit(0) in subclass::getPtr().

Since p is a "base" and getPtr() is not virtual, I would expect the
compiler to generate a call to base::getPtr(). Since base doesn't have
an isA() method in this code, I'd expect it to fail. Does it actually
compile, or does your real code have a base::isA() method?
see above and note that the compiler error was in the OP...the virtual
nature of getPtr() has been verified but the compiler wont recognize the
subclass* return value of getPtr() to allow access to subclass::isA().

What I'm seeing is weird because the epxression p->getPtr() should return
a subclass* and that return type should be compatible with subclass::isA().
Oct 31 '07 #3
On 2007-10-31 06:49, Just me wrote:
On Wed, 31 Oct 2007 05:11:31 +0000, Tim H wrote:
>>
I think you're stuck. Why not make a virtual SerializeIt() method
instead?

Serialization is not a problem and that part works. The problem is
that deserialization is pretty much useless if I still have to do
an explicit cast from a base pointer type back to the correct
subclass in the heirarchy upon object reconstruction.
>>struct base {
virtual base* getPtr()=0;};

struct subclass: public base {
subclass* getPtr() { return this; }
const char* isA() { return "subclass"; }

};

getPtr() is not virtual so it is statically bound based on the type,
which is known at compile time.

If you look closely you will see that getPtr() is declared virtual in the
base class and the correct sublcass::getPtr() is being called. I verified
this by inserting an exit(0) in subclass::getPtr().
What Tim meant was that you are not allowed to change the return type of
a virtual function. However, returning a type that is a subtype of the
original function's is allowed, but that does not help you.
>Since p is a "base" and getPtr() is not virtual, I would expect the
compiler to generate a call to base::getPtr(). Since base doesn't have
an isA() method in this code, I'd expect it to fail. Does it actually
compile, or does your real code have a base::isA() method?

see above and note that the compiler error was in the OP...the virtual
nature of getPtr() has been verified but the compiler wont recognize the
subclass* return value of getPtr() to allow access to subclass::isA().

What I'm seeing is weird because the epxression p->getPtr() should return
a subclass* and that return type should be compatible with subclass::isA().
No, the pointer p is of of type base*, that means that the function
called is base's getPtr() (but the code that is executed is one in
subclass) which means that the type of the pointer that is returned from
getPtr() have the type declared in base's getPtr(), namely base*.

With a pointer to base you can only call base's functions. Though if
they are virtual and the actual type of the object pointed to is a
derived type then the implementation in the derived type will be used.
But it is still the base's function that was called. What you can do is
make isA() a virtual function in base, and use the value returned to
dynamic_cast() the pointer to the correct subtype.

--
Erik Wikström
Oct 31 '07 #4
Me
On Wed, 31 Oct 2007 08:21:04 +0000, Noone wrote:
No, the pointer p is of of type base*, that means that the function
called is base's getPtr() (but the code that is executed is one in
subclass) which means that the type of the pointer that is returned from
getPtr() have the type declared in base's getPtr(), namely base*.

With a pointer to base you can only call base's functions. Though if
they are virtual and the actual type of the object pointed to is a
derived type then the implementation in the derived type will be used.
But it is still the base's function that was called. What you can do is
make isA() a virtual function in base, and use the value returned to
dynamic_cast() the pointer to the correct subtype.
then it is still an exercise in futility because the whole purpose was to
avoid having to do an explicit cast through some switch() statement...so
unless dynamic_cast<takes runtime computed values as its template
argument, then all is for not...

regarding changing the return type of a virtual: the compiler should
warn me of this if it is not allowed...The assumption was that it is
allowed since there was no compiler error there and the correct
getPtr() virtual was being executed.
thanks.
Oct 31 '07 #5
On 2007-10-31 17:39, Me wrote:
On Wed, 31 Oct 2007 08:21:04 +0000, Noone wrote:
>No, the pointer p is of of type base*, that means that the function
called is base's getPtr() (but the code that is executed is one in
subclass) which means that the type of the pointer that is returned from
getPtr() have the type declared in base's getPtr(), namely base*.

With a pointer to base you can only call base's functions. Though if
they are virtual and the actual type of the object pointed to is a
derived type then the implementation in the derived type will be used.
But it is still the base's function that was called. What you can do is
make isA() a virtual function in base, and use the value returned to
dynamic_cast() the pointer to the correct subtype.

then it is still an exercise in futility because the whole purpose was to
avoid having to do an explicit cast through some switch() statement...so
unless dynamic_cast<takes runtime computed values as its template
argument, then all is for not...
No, it does not.
regarding changing the return type of a virtual: the compiler should
warn me of this if it is not allowed...The assumption was that it is
allowed since there was no compiler error there and the correct
getPtr() virtual was being executed.
As I said, it is not allowed. But in your case you did not actually
change the return type as much as being a little more specific about it.
The getPtr in base returned a pointer to base, while the getPtr() in
subclass returned a pointer to a subclass. And since a pointer to a
subclass is (or rather is convertible to) a pointer to base the return
type was not changed. And you were correct in assuming the correct
getPtr() was executed.

--
Erik Wikström
Oct 31 '07 #6
On Oct 31, 9:21 am, Erik Wikström <Erik-wikst...@telia.comwrote:
On 2007-10-31 06:49, Just me wrote:
On Wed, 31 Oct 2007 05:11:31 +0000, Tim H wrote:
[...]
If you look closely you will see that getPtr() is declared
virtual in the base class and the correct sublcass::getPtr()
is being called. I verified this by inserting an exit(0) in
subclass::getPtr().
What Tim meant was that you are not allowed to change the
return type of a virtual function. However, returning a type
that is a subtype of the original function's is allowed, but
that does not help you.
What you meant is that returning a pointer or a reference to a
derived type when the function in the base class returns a
pointer or reference to a base is legal. It's called co-variant
return. But of course, the type of the pointer which gets used
at the call site is determined statically. If the static type
is base*, it can only be used to call functions declared in
base. Regardless of what the base* really points to.
Since p is a "base" and getPtr() is not virtual, I would
expect the compiler to generate a call to base::getPtr().
Since base doesn't have an isA() method in this code, I'd
expect it to fail. Does it actually compile, or does your
real code have a base::isA() method?
see above and note that the compiler error was in the
OP...the virtual nature of getPtr() has been verified but
the compiler wont recognize the subclass* return value of
getPtr() to allow access to subclass::isA().
What I'm seeing is weird because the epxression p->getPtr()
should return a subclass* and that return type should be
compatible with subclass::isA().
No, the pointer p is of of type base*, that means that the
function called is base's getPtr() (but the code that is
executed is one in subclass)
Only if the function is virtual. Basically, the entire call
sequence is first resolved (overloading, etc.) statically.
Then, if and only if the chosen function is declared virtually,
the compiler will invoke the function of the most derived class.
But before any such considerations, the compiler must see a
declaration of the function. Using purely static analysis.

FWIW, this is a standard behavior of a statically typed
language. It's not specific to C++: Java, C# and I believe
Ada95 and Eiffel all have the same behavior. If you want
something different, you need a fully dynamically typed
language, like Lisp or Smalltalk. Which has other
disadvantages: whatever language you choose represents a
compromise between safety and flexibility (with C++ leaning
very, very strongly to the side of safety).
which means that the type of the pointer that is returned from
getPtr() have the type declared in base's getPtr(), namely
base*.
With a pointer to base you can only call base's functions.
Though if they are virtual and the actual type of the object
pointed to is a derived type then the implementation in the
derived type will be used. But it is still the base's
function that was called.
I know what you're trying to say, but that sounds a bit
confusing, since of course, you don't actually call the function
in base---if it is pure virtual, there is no function to call.
I prefer to explain it in terms of compile time "resolution"
(given that we already have to term "overload resolution"). The
compiler must first choose which function to call, statically;
how can it know if the function is virtual until it has choosen
it?

The actual "resolution" is a fairly complex process, involving
name lookup, including ADL, then type deduction on template
parameters, and finally overload resolution. Having "resolved"
the function, the compiler then does things like access checks
(private, etc.), and only after all this does it consider
whether the function is virtual or not, and either call the
function in the statically declared type or the one in the
dynamic type.
What you can do is make isA() a virtual function in base, and
use the value returned to dynamic_cast() the pointer to the
correct subtype.
There are a number of possible solutions, but since we don't
really know the problem...

--
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

Nov 1 '07 #7

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

Similar topics

1
by: Gerry Sutton | last post by:
Hi All! I have noticed a strange behavior when using a constant identifier to initialize an instance list variable in a base class and then trying to modifying the list in subclasses by using...
2
by: Steven T. Hatton | last post by:
I find the surprising. If I derive Rectangle from Point, I can access the members of Point inherited by Rectangle _IF_ they are actually members of a Rectangle. If I have a member of type Point...
4
by: pramod8378 | last post by:
#include <iostream.h> class Simple { public : void memfunction() { cout << "Hello I am in memFunction" ; } }; Simple *objSimple ;
6
by: harry | last post by:
Hi ppl I have a question about memory layout of a class. Consider the code below: class Base1 { virtual void f() { cout << "Base1::f" << endl; } virtual void g() { cout << "Base1::g" <<...
14
by: Glen Dayton | last post by:
While looking at some old code I ran across a snippet that increments a pointer to access different members of a structure: .... struct Badness { std::string m_begin; std::string m_param1;...
9
by: vilarneto | last post by:
Hello everyone, Today I started to use template specializations in a project and suddenly faced a curious problem. Following is a complete example that shows the situation: ---------- ...
3
by: orkonoid | last post by:
Hello, I am having trouble with a Polymorphism issue using container classes. I have a longwinded and shortwinded version of my question: Shortwinded version: How can I store base class...
6
by: Bhawna | last post by:
I am into c++ code maintenance for last 3-4 years but recently I am put into design phase of a new project. Being a small comapany I dont have enough guidance from seniors. Currently I am into a...
0
by: DolphinDB | last post by:
Tired of spending countless mintues downsampling your data? Look no further! In this article, you’ll learn how to efficiently downsample 6.48 billion high-frequency records to 61 million...
0
by: ryjfgjl | last post by:
ExcelToDatabase: batch import excel into database automatically...
0
isladogs
by: isladogs | last post by:
The next Access Europe meeting will be on Wednesday 6 Mar 2024 starting at 18:00 UK time (6PM UTC) and finishing at about 19:15 (7.15PM). In this month's session, we are pleased to welcome back...
0
by: Vimpel783 | last post by:
Hello! Guys, I found this code on the Internet, but I need to modify it a little. It works well, the problem is this: Data is sent from only one cell, in this case B5, but it is necessary that data...
0
by: ArrayDB | last post by:
The error message I've encountered is; ERROR:root:Error generating model response: exception: access violation writing 0x0000000000005140, which seems to be indicative of an access violation...
1
by: CloudSolutions | last post by:
Introduction: For many beginners and individual users, requiring a credit card and email registration may pose a barrier when starting to use cloud servers. However, some cloud server providers now...
1
by: Defcon1945 | last post by:
I'm trying to learn Python using Pycharm but import shutil doesn't work
1
by: Shællîpôpï 09 | last post by:
If u are using a keypad phone, how do u turn on JavaScript, to access features like WhatsApp, Facebook, Instagram....
0
by: Faith0G | last post by:
I am starting a new it consulting business and it's been a while since I setup a new website. Is wordpress still the best web based software for hosting a 5 page website? The webpages will be...

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.