473,396 Members | 1,975 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,396 software developers and data experts.

Trying to understand casting, from base to derived.

Hi,

If I have two classes.

Class A
{
public:
A( const char *sz);
~A();
virtual void Foo() = 0;
}

Class B : public A
{
public:
B(const char *sz) : A( sz ) {};
~B(){ /* do clean up */ };
virtual void Foo();

int iSomeObject;
char *pSomePointer;
}

if i do

A *test = new A();
//
// is it then safe to do
//

((B *)test)->Foo();

// or even
((B *)test)->iSomeObject = 10

//////////////////////////////////////////////
Why do I ask?

because my base class reads information from a file.
So it is easier for me to have one call

A * test = new A( /* file name to read */ )

Depending on the actual data in the file a certain base class will be
used...

I could do

B * test = new B( /* file name to read */ )

but as I said, I only know what derived class to use after the file has been
read.
I guess I could do it the long way around, (read the file and depending on
the type call the relevant derived class), but that does not seem very
efficient.

To make matters worse I want to save all the pointers in a vector.

std::vector< A* >

but is it safe to include derived classes pointer in a vector?

Many thanks in advance for your help/advices.

Simon
Aug 26 '05 #1
15 1280
Simon wrote:

Hi,

If I have two classes.

Class A
{
public:
A( const char *sz);
~A();
virtual void Foo() = 0;
}

Class B : public A
{
public:
B(const char *sz) : A( sz ) {};
~B(){ /* do clean up */ };
virtual void Foo();

int iSomeObject;
char *pSomePointer;
}

if i do

A *test = new A();
//
// is it then safe to do
//

((B *)test)->Foo();
No. test points to an object of type A, not B.

// or even
((B *)test)->iSomeObject = 10
No. test points to an object of type A. Such an object
doesn't have a member iSomeObject. No memory space
was reserved for such a member, since your new requested
an A object, not a B.

//////////////////////////////////////////////
Why do I ask?

because my base class reads information from a file.
So it is easier for me to have one call

A * test = new A( /* file name to read */ )

Depending on the actual data in the file a certain base class will be
used...

I could do

B * test = new B( /* file name to read */ )

but as I said, I only know what derived class to use after the file has been
read.
Change your file format.
In the format insert codes which guide the reader, such that it knows which
object to create. -> You know what derived class *during* you read the file
and hence can create the correct object.
I guess I could do it the long way around, (read the file and depending on
the type call the relevant derived class), but that does not seem very
efficient.
As said: Change your file format. It is always possible to augument the file
with information, such that the reader can figure out what to do.

To make matters worse I want to save all the pointers in a vector.

std::vector< A* >

but is it safe to include derived classes pointer in a vector?


That's fine.
Every A pointer can always point to any other class dervied from A.

--
Karl Heinz Buchegger
kb******@gascad.at
Aug 26 '05 #2
Simon ha scritto:
Class A
{
public:
A( const char *sz);
~A();
virtual void Foo() = 0;
}

Class B : public A
{
public:
B(const char *sz) : A( sz ) {};
~B(){ /* do clean up */ };
virtual void Foo();

int iSomeObject;
char *pSomePointer;
}
You can't do that, vitual pure classes can't be instantied A *test = new A();
It's illegal, you are trying to call a B::method on A ((B *)test)->Foo();
((B *)test)->iSomeObject = 10


B IS-A A, but not viceversa

A test = new B('stuffstring');

then you can :

test->Foo(); // LEGAL
test->iSomeObject = 0; // ERROR

class B {/*...*/};
class D : public B {/*.../*};

D is-a B, but B isn't D.

when you (publicly) extend a class you may both change behavior and
adding features, and the base class don't have to know anything about it
(so you can force B to use functions declared only in D).

It seems your had understood inheritance in the opposite way.

Bye,
Giulio

Aug 26 '05 #3

"Karl Heinz Buchegger" <kb******@gascad.at> wrote in message
news:43***************@gascad.at...
Simon wrote:

Change your file format.
In the format insert codes which guide the reader, such that it knows
which
object to create. -> You know what derived class *during* you read the
file
and hence can create the correct object.
I guess I could do it the long way around, (read the file and depending
on
the type call the relevant derived class), but that does not seem very
efficient.


As said: Change your file format. It is always possible to augument the
file
with information, such that the reader can figure out what to do.

To make matters worse I want to save all the pointers in a vector.

std::vector< A* >

but is it safe to include derived classes pointer in a vector?


That's fine.
Every A pointer can always point to any other class dervied from A.


Thanks for that.
One last question.

When it comes time to delete all the pointers in the vector, I would
normally do

A *pSomePointer = (*(m_vectorData.begin()+nPos));
delete pSomePointer;

if pSomePointer was created with the derived class B will the destructor of
B be called or the destructor of A?

Simon
Aug 26 '05 #4
Simon wrote:
Depending on the actual data in the file a certain base class will be
used...


I think you wanted to say "certain derived class will be used"?
There are two operations here.

1. Finding the "type" of the file.
2. Calling the appropriate derived class mf to process the file.

You could have the base class interface as

class Base {
public:
void process_file( const string& fileName)
{
process_file( find_file_type(fileName) );
}
protected:
virtual void process_file(const FileType&);
// each derived class will take care of its own
// FileType
private:
FileType find_file_type( const string& fileName);
};

An object of FileType will have the opened file descriptor or
FILE* or an ifstream or whatever. This, so that you don't have
to re-open the file or re-initialize the stream.

By doing this, you are having clear separation of responsibilities.
It is the responsibility of the base class to determine the type
of file. And it is the responsibility of the derived class to
process the file.

Any comments on this approach?

Rgds,
anna

Aug 26 '05 #5
Simon ha scritto:

When it comes time to delete all the pointers in the vector, I would
normally do

A *pSomePointer = (*(m_vectorData.begin()+nPos));
delete pSomePointer;

if pSomePointer was created with the derived class B will the destructor of
B be called or the destructor of A?


If you are using interface(or public) inheritance you had to declare a
destructor like this :

class B
{
/* ... */
public:
virtual ~B() throw();
/* ... */
}

class D : public B
{
/* ... */
public:
virtual ~D() throw();
/* ... */
}

so in case of :

B *b = new D();
/* ... */
delete b;

D::~D 'll do the complete requested cleanup and the operator delete'll
free the right amount of memeory, with a non-virtual destructor B::~B
'll do its cleanup only.

the "throw()" on the method signature is exception-safe 'cause operator
delete can't throw any exception by definition, and whatever may happen
during the dctor call, the destruction must be completed.

bye,
Giulio
Aug 26 '05 #6

"Simon" <sp********@example.com> wrote in message
news:3n***********@individual.net...

"Karl Heinz Buchegger" <kb******@gascad.at> wrote in message
news:43***************@gascad.at...
Simon wrote:

Change your file format.
In the format insert codes which guide the reader, such that it knows
which
object to create. -> You know what derived class *during* you read the
file
and hence can create the correct object.
I guess I could do it the long way around, (read the file and depending
on
the type call the relevant derived class), but that does not seem very
efficient.
As said: Change your file format. It is always possible to augument the
file
with information, such that the reader can figure out what to do.

To make matters worse I want to save all the pointers in a vector.

std::vector< A* >

but is it safe to include derived classes pointer in a vector?


That's fine.
Every A pointer can always point to any other class dervied from A.


Thanks for that.
One last question.

When it comes time to delete all the pointers in the vector, I would
normally do

A *pSomePointer = (*(m_vectorData.begin()+nPos));
delete pSomePointer;


Why don't you use the subscript [] operator which would make the syntax more
legible?

if pSomePointer was created with the derived class B will the destructor
of B be called or the destructor of A?

Simon


You can certainly do this but you need to have the destructor of the base
class declared virtual!
See http://www.parashift.com/c++-faq-lit....html#faq-20.7

HTH
Chris
Aug 26 '05 #7
>>
When it comes time to delete all the pointers in the vector, I would
normally do

A *pSomePointer = (*(m_vectorData.begin()+nPos));
delete pSomePointer;

D::~D 'll do the complete requested cleanup and the operator delete'll
free the right amount of memeory, with a non-virtual destructor B::~B 'll
do its cleanup only.
Thanks for that, in a way it makes sense.

the "throw()" on the method signature is exception-safe 'cause operator
delete can't throw any exception by definition, and whatever may happen
during the dctor call, the destruction must be completed.
That, I did not know.

bye,
Giulio


Thanks

Simon
Aug 26 '05 #8
>>
A *pSomePointer = (*(m_vectorData.begin()+nPos));
delete pSomePointer;
Why don't you use the subscript [] operator which would make the syntax
more legible?


It's one of many weird habit I pick-up along the way.

if pSomePointer was created with the derived class B will the destructor
of B be called or the destructor of A?

Simon


You can certainly do this but you need to have the destructor of the base
class declared virtual!
See http://www.parashift.com/c++-faq-lit....html#faq-20.7


Thanks, i just wan't sure.

HTH
Chris


Simon
Aug 26 '05 #9
Depending on the actual data in the file a certain base class will be
used...
I think you wanted to say "certain derived class will be used"?


Indeed.
There are two operations here.

1. Finding the "type" of the file.
2. Calling the appropriate derived class mf to process the file.
<snip code>
An object of FileType will have the opened file descriptor or
FILE* or an ifstream or whatever. This, so that you don't have
to re-open the file or re-initialize the stream.

By doing this, you are having clear separation of responsibilities.
It is the responsibility of the base class to determine the type
of file. And it is the responsibility of the derived class to
process the file.

Any comments on this approach?
It does look quite good. I am not sure about 2 separate classes, but it is
as good as any way I guess.
I will probably go down that road.

Rgds,
anna


Simon
Aug 26 '05 #10
Giulio Guarnone <ge**********@tiscali.it> wrote in
news:43***********************@authen.white.readfr eenews.net:
the "throw()" on the method signature is exception-safe 'cause
operator delete can't throw any exception by definition, and whatever
may happen during the dctor call, the destruction must be completed.


That safety is somewhat illusory.... if an exception does happen to be
thrown during the destruction, an exception _will_ escape your destructor:
std::unexpected.

Aug 26 '05 #11
Andre Kostur ha scritto:
Giulio Guarnone <ge**********@tiscali.it> wrote in
news:43***********************@authen.white.readfr eenews.net:

the "throw()" on the method signature is exception-safe 'cause
operator delete can't throw any exception by definition, and whatever
may happen during the dctor call, the destruction must be completed.

That safety is somewhat illusory.... if an exception does happen to be
thrown during the destruction, an exception _will_ escape your destructor:
std::unexpected.


yes, and then program exit, it should be an unexpected (not managable)
event. No inconsistent objects will be used.

Bye,
Giulio
Aug 26 '05 #12
Ben
Simon wrote:

A * test = new A( /* file name to read */ )

Depending on the actual data in the file a certain base class will be
used...

I could do

B * test = new B( /* file name to read */ )

but as I said, I only know what derived class to use after the file has been
read.
I guess I could do it the long way around, (read the file and depending on
the type call the relevant derived class), but that does not seem very
efficient.


Research the Abstract Factory pattern.

Ben
--
I'm not just a number. To many, I'm known as a String...
Aug 26 '05 #13
Simon: Your final question was?

"To make matters worse I want to save all the pointers in a vector
std::vector< A* >
but is it safe to include derived classes pointer in a vector?"

You could try using boost::shared_ptr. Please see the link
www.boost.org.

Aug 26 '05 #14
Simon, One small nitpick . Your abstract base class A does not have a
virtual destructor. If you want your derived base class B's destructor
to function correctly you need to your destructor in class A virtual.
Thank you.

Aug 28 '05 #15
Simon, As the following shows, the boost shared_ptr simplifies the
memory management for yout std::vector. When the vector goes out of
scope, all the elements in the vector that are not in use get
automatically destroyed:

class ATest
{
public:
ATest(const char *sz){ptr = new char[25];
strncpy(ptr, sz, strlen(sz));};
virtual ~ATest(){cout << "deleting ATest" << endl;};
virtual void Foo(){cout << "ATest foo" << endl;};
private:
char* ptr;
};

class BTest : public ATest
{
public:
BTest(const char *sz, int some = 0, char* ptr = NULL)
: ATest( sz ), iSomeObject(some),
pSomePointer(new char[25])
{ strcpy(pSomePointer, ptr); };
~BTest(){cout << "deleting BTest" << endl;};
virtual void Foo(){cout << "BTest foo" << endl;};

private:
int iSomeObject;
char *pSomePointer;
};

typedef std::vector< boost::shared_ptr<ATest> > ListOfObjects;

class DoesSomething
{
public:
DoesSomething() {};

ListOfObjects returnList()
{
ListOfObjects lst;
lst.push_back(boost::shared_ptr<ATest>(
new BTest("abcdef", 10, "hjklmnop") ));
lst.push_back(boost::shared_ptr<ATest>(
new ATest("clara")));
return lst;
}
};
int _tmain(int argc, _TCHAR* argv[])
{
using namespace boost;
using namespace std;

DoesSomething d;
ListOfObjects lst = d.returnList();
boost::shared_ptr<ATest> aptr = lst[0];
boost::shared_ptr<ATest> claraptr = lst[1];
aptr->Foo();
claraptr->Foo();
}

Thank you.

Aug 28 '05 #16

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

Similar topics

5
by: Suzanne Vogel | last post by:
** Isn't the 'static_cast' operator the same as traditional type casting? ie, Aren't the following ways of getting b1, b2 the same? // 'Derived' is derived from 'Base' Derived* d = new...
7
by: Jakob Bieling | last post by:
Hi, I have a question about casting and using the casted pointer: Suppose I have a 'base' class and a 'derived' class (which is derived from 'base'). Now I have this scenario: base* p1 = new...
14
by: jimmy | last post by:
Hi, Please forgive me if this is elementary. I can't seem to find the solution anywhere. // foo() is only declared/defined in Derived Base* base = new Derived(); ((Derived*)base)->foo(); ...
10
by: Brett Romero | last post by:
Say I have a class inheriting some base class: BaseClass { void Foo() { Update(); } }
24
by: AtariPete | last post by:
Hey All, I have a C# question for you regarding up casting (base to derived). I was wondering about the most elegant way (readable, less code) to cast from a base type to its derived type....
4
by: propokergrad | last post by:
Hello, say I have two classes: class Base{...}; class Derived : public Base{...} I would like to do something similar to this: std::vector<Base*>::iterator b;...
9
by: Jess | last post by:
Hello, It seems both static_cast and dynamic_cast can cast a base class pointer/reference to a derived class pointer/reference. If so, is there any difference between them? In addition, if I...
9
by: Taras_96 | last post by:
Hi everyone, I was experimenting with static_cast and reinterpret cast #include <iostream> struct A1 { int a; }; struct A2 { double d; }; struct B : public A1, A2
0
by: akshaycjoshi | last post by:
I am reading a book which says Even though unboxed value types don't have a type object pointer, you can still call virtual methods (such as Equals, GetHashCode, or ToString) inherited or...
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: nemocccc | last post by:
hello, everyone, I want to develop a software for my android phone for daily needs, any suggestions?
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:
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
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...
0
by: Hystou | last post by:
Overview: Windows 11 and 10 have less user interface control over operating system update behaviour than previous versions of Windows. In Windows 11 and 10, there is no way to turn off the Windows...
0
tracyyun
by: tracyyun | last post by:
Dear forum friends, With the development of smart home technology, a variety of wireless communication protocols have appeared on the market, such as Zigbee, Z-Wave, Wi-Fi, Bluetooth, etc. Each...
0
agi2029
by: agi2029 | last post by:
Let's talk about the concept of autonomous AI software engineers and no-code agents. These AIs are designed to manage the entire lifecycle of a software development project—planning, coding, testing,...

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.