473,396 Members | 1,738 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.

Redefine a member variable in a derived class

If I have:

class A
{
public:
class some_base_class **Obj;
};

And I would like to redefine "Obj" in a class derived from class A,
something like this maybe:

class B : public A
{
public:
class some_other_class **Obj;
};

How would I do that, or is it even possible? If I just use the above
method, class B ends up getting a second copy of Obj, so anything done
to Obj in the base class isn't working with the same pointers... that
isn't what I want.

The reason I want to do this is because class B creates different
objects for the "Obj" array. Whenever I reference Obj from a class B
object I'd like to be able to do it without type-casting. I currently
have something like this all over my code:

TNameRecord *nr = (TNameRecord*) NameRecs->Obj[x];

I'd like to just be able to do this:

TNameRecord *nr = NameRecs->Obj[x];

And if I accidently did this, I'd expect a compiler error:

TNameRecord *nr = MessageRecs->Obj[x];

Because MessageRecs uses some other type of object.

I've searched all over the newsgroups and can't find what I'm looking
for, although I'm sure this question has already been answered. I
guesss I just don't know what the terms are that I need to search for.

Sep 8 '05 #1
6 5845
es***@surfbest.net wrote:
If I have:

class A
{
public:
class some_base_class **Obj;
};

And I would like to redefine "Obj" in a class derived from class A,
something like this maybe:

class B : public A
{
public:
class some_other_class **Obj;
};

How would I do that, or is it even possible?
It is possible, allowed, legal. Just do it. What seems to be the
problem?
If I just use the above
method, class B ends up getting a second copy of Obj,
Yes. Its own. Every class has its own data.
so anything done
to Obj in the base class isn't working with the same pointers... that
isn't what I want.
Of course not. What *do* you want?
The reason I want to do this is because class B creates different
objects for the "Obj" array.
Uh... Then why is 'B' derived from 'A'?
Whenever I reference Obj from a class B
object I'd like to be able to do it without type-casting. I currently
have something like this all over my code:

TNameRecord *nr = (TNameRecord*) NameRecs->Obj[x];

I'd like to just be able to do this:

TNameRecord *nr = NameRecs->Obj[x];

And if I accidently did this, I'd expect a compiler error:

TNameRecord *nr = MessageRecs->Obj[x];

Because MessageRecs uses some other type of object.

I've searched all over the newsgroups and can't find what I'm looking
for, although I'm sure this question has already been answered. I
guesss I just don't know what the terms are that I need to search for.


It is possible that you just don't know what you really need and why...

Why is your 'B' derived from 'A'? Does the LSP apply here? If 'B' needs
to change 'A' so much as to replace such _implementation_detail_ as one of
the 'A's *data members* with some other thing, then you are most likely
applying _inheritance_ without merit.

Perhaps you need to generalize your class[es] and have a template instead?
Then you can instantiate it for different types:

template<class T>
struct AB {
T **Obj;
};

typedef AB<TMessageRecord> A;
typedef AB<TNameRecord> B;
....
A MessageRecs;
B NameRecs;
....

V
Sep 8 '05 #2
In order to explain why I think inheritance is the correct approach,
take the following objects for example:

class TRecord
{
public:
long ID;
};

class TRecords
{
public:
TRecord **Rec;
void Sort(void);
void SortByID(void);
virtual int Compare(TRecord *r1,TRecord *r2)=0;
};

class TNameRecord : public TRecord
{
public:
char Name[21];
};

class TNameRecords
{
public:
TNameRecord* Add(void);
int Compare(TRecord *r1,TRecord *r2);
};

By using inheritance I can have 99% of the record sorting code in
TRecords::Sort(). TRecords::Sort() can have all kinds of code to do a
Bubble Sort, a Quick Sort, Binary, B-Tree, etc... The only thing the
derived classes need to provide are a compare function.

Each derived class creates an object derived from TRecord (the Add()
function does this), which is added to the "Rec" array of the base
class. Since they can create their own objects to add to the Rec
array, they can store any type of data. However, since each object
they add to the array must be derived from TRecord, the base class is
able to perform a SortByID() without any code in the derived class.
Also, it isn't show here, but TRecord has a virtual destructor, so the
base class is also able to free all objects when it is destroyed. The
base class can also have methods such as Search(), Move(), and Delete()
(since it can safely delete the objects due to the virtual
destructors).

All of this works well for me, and I think it is a good design. I've
seen it used in MFC and Borland's VCL a lot (TObjectList, TList,
TStringList). They usually use void* or other generic pointers, but in
my case I want to use specific pointer types for each derived class,
instead of having to typecast all of the time. Because, anytime I'm
using TNameRecords::Rec, I *know* that the pointers are always going to
point to a TNameRecord, and I'd like to catch bugs at compile time if I
accidently mix pointer types.

One way I've seen to handle this problem would be to add a function to
TNameRecords, like this (a "getter"):

TNameRecord* TNameRecords::getRecAsNameRecord(int index)
{
return((TNameRecord*)Rec[index]);
}

The function name could be anything, I just used that long name to make
the point clear.

However, I don't like this method because it seems like that adds
overhead both to the execution of the code, and to the size of the code
(the EXE file size). If I use __inline functions I guess it may not
add overhead to execution? But it will still increase the EXE size I
would imagine.

Sep 8 '05 #3
<es***@surfbest.net> wrote in message
news:11**********************@z14g2000cwz.googlegr oups.com...
In order to explain why I think inheritance is the correct approach,
take the following objects for example:

class TRecord
{
public:
long ID;
};
It will be better if you kept TRecord as an interface class. At least with a
virtual destructor... (I just realized that you mention this below.)

Also, it is not clear at all what that 'T' is doing at the beginning of the
name.

class TRecords
{
public:
TRecord **Rec;
void Sort(void);
void SortByID(void);
virtual int Compare(TRecord *r1,TRecord *r2)=0;
};
Instead of defining TRecords, typedef it from a standard container:

typedef std::vector<TRecord *> TRecords;

But that will give you resource management problems. Wrap your dynamic
objects in smart pointers:

#include <boost/shared_ptr.hpp>

/* ... */

typedef boost::shared_ptr<TRecord> TRecordPtr;

typedef std::vector<TRecordPtr> TRecords;

class TNameRecord : public TRecord
{
public:
char Name[21];
};
Fine...
class TNameRecords
{
public:
TNameRecord* Add(void);
int Compare(TRecord *r1,TRecord *r2);
};
Same comments apply for TNameRecords; but you can use TRecords to hold
TNameRecord objects too, because TNameRecord *is-a* TRecord.
By using inheritance I can have 99% of the record sorting code in
TRecords::Sort().
Regardless of inheritance, you can have 100% of record sorting code in a
free function. I suggest you spend a few days on the standard library.
Josuttis's "The C++ Standard Library" book is an excellent book.
Also, it isn't show here, but TRecord has a virtual destructor, so the
base class is also able to free all objects when it is destroyed.
Still, you will have to call the destructors explicitly through delete.
Needing to call delete explicitly, is an indication of design problems.
All of this works well for me, and I think it is a good design.
Standard library's separation of containers and algorithms is a good design
too.
I've
seen it used in MFC and Borland's VCL a lot (TObjectList, TList,
TStringList).
I don't know about VCL, but MFC was written before modern C++ features
and/or techniques were accepted.
They usually use void* or other generic pointers,
There you go! :)
but in
my case I want to use specific pointer types for each derived class,
instead of having to typecast all of the time. Because, anytime I'm
using TNameRecords::Rec, I *know* that the pointers are always going to
point to a TNameRecord, and I'd like to catch bugs at compile time if I
accidently mix pointer types.

One way I've seen to handle this problem would be to add a function to
TNameRecords, like this (a "getter"):

TNameRecord* TNameRecords::getRecAsNameRecord(int index)
{
return((TNameRecord*)Rec[index]);
}

No matter what, use one of C++'s casting operators. I think you want to use
static_cast above. The compiler provides no help for C-style casts.
However, I don't like this method because it seems like that adds
overhead both to the execution of the code, and to the size of the code
(the EXE file size). If I use __inline functions I guess it may not
add overhead to execution?
The function overhead is a myth until the application is tested and it is
proven to be so. Use functions generously.
But it will still increase the EXE size I
would imagine.


You can't know that. With or without using the inline keyword, the compiler
will do whatever it sees fit. The non-standard __inline keyword may be
different...

Ali

Sep 8 '05 #4
es***@surfbest.net wrote:
If I have:

class A
{
public:
class some_base_class **Obj;
};

And I would like to redefine "Obj" in a class derived from class A,
something like this maybe:

class B : public A
{
public:
class some_other_class **Obj;
};

How would I do that, or is it even possible? If I just use the above
method, class B ends up getting a second copy of Obj


class A
{
Base **Obj;
public:
virtual Base **getObj() { return Obj; }
};

class B: public A
{
Derived **Obj;
public:
virtual Base **getObj() { return Obj; }
};

Then use getObj() whenever you want to refer to Obj.
You can't have polymorphic variables, only functions.

Sep 8 '05 #5
Thanks to all who replied, and sorry if my quoting isn't very good
(Google seems to have taken a step backwards in that area, I may need
to find a new news reader).

I obviously have a lot to learn about C++ still, especially when it
comes to templates and C++ style casts. I'm more of an OO C
programmer, if you know what I mean. I have read about polymorphism,
and I think that is what I was looking for, which I guess can't be done
for variables.

I'll do some learning about the smart pointers and templates, however
for this project I'll probably just use the get() function route, since
that will require less changes to existing/tested code.

p.s.- The "T" in the object name has to do with the company I work for.
I think we've used that longer than Borland! Not sure why Borland
uses T also, it has been a problem in a couple places (duplicate class
names, and duplicate namespaces even, if you can beleive it), must go
back to their "Turbo" line of compilers.

Sep 9 '05 #6
es***@surfbest.net wrote:
Thanks to all who replied, and sorry if my quoting isn't very good
(Google seems to have taken a step backwards in that area, I may need
to find a new news reader).
Click the "options" link, and post from what you get there.
It will quote the whole message and you can edit and snip.
I obviously have a lot to learn about C++ still,

[snip]

I think all but a very small number of coders could reasonably
say that. A few of the best posters here probably are "up" on
nearly the entire language, but even the best make small mistakes
now and then.

Get yourself some of the better intro/intermediate texts.
Check out www.accu.org and the book reviews there. My
personal suggestions for early reading:

- Accelerated C++ by Koenig and Moo.
- Just about anything by Scott Meyers.
- Just about anything by Herb Sutter.

And, of course, you need Stroustrup's The C++ Programming Language.
Socks

Sep 9 '05 #7

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

Similar topics

8
by: Ernst Murnleitner | last post by:
Hello Readers, Is there a way that only one class can construct a class A and its inherited classes A2, A3 etc.? I want to construct a class A (and the inherited classes A2, A3 etc.) from a...
1
by: none | last post by:
Hi, I have a base class with a pointer-to-member function variable. Then I have a derived class that needs to use that variable to call a member function (with the same arguments and return value...
5
by: Bob | last post by:
I want to find a way to detect the existance of the private member of a particular type in the derived class from inside the base class itself and call its Dispose() method. Reflection GetFields()...
2
by: Mark Sisson | last post by:
Hi all. SITUATION ================ 1. I have a base class with a member variable that's an object 2. I have several classes that inherit from the base class. 3. There are several methods in...
7
by: Valeriu Catina | last post by:
Hi, consider the Shape class from the FAQ: class Shape{ public: Shape(); virtual ~Shape(); virtual void draw() = 0;
15
by: Bob Johnson | last post by:
I have a base class that must have a member variable populated by, and only by, derived classes. It appears that if I declare the variable as "internal protected" then the base class *can*...
4
by: RSH | last post by:
Hi, I have a situation where I have a class which manages different data connections. In trying to enforce encapsulation I have a member field called connection which could be a type of...
3
by: Goran | last post by:
Hi @ all! Is it possible to overload a member variable? Example: class ClassA_t {
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
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...
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
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.