473,748 Members | 5,242 Online
Bytes | Software Development & Data Engineering Community
+ Post

Home Posts Topics Members FAQ

"array of Derived" is not a kind-of "array of Base" question

Fellow hackers,

I have a class BuildNode that inherits from class Node.

Similarly, I have a class BuildTree that inherits from class Tree.

Tree includes a member variable:
vector<Node> nodes; // For clarity, let this be "orig_nodes "

BuildTree includes a member variable:
vector<BuildNod e> nodes; // For clarity, let this be "build_node s"

So as far as I can tell, this overloads "nodes", defining two different
"nodes" variables instead of having build_nodes clobber orig_nodes (as
was my intention).

Now, let's say I have a Tree method defined:
bool Tree::is_degene rate const { return nodes.empty(); }

If I have a BuildTree object build_tree, and I call
build_tree.is_d egenerate(), it returns "orig_nodes.emp ty()", not
"build_nodes.em pty()" as is desired.

So the question is:
Is there any way to define methods in Tree that reference "nodes", and
get those methods to act upon "build_node s" if the calling object is a
BuildTree and "orig_nodes " if the calling object is a Tree, without
duplicating the code in BuildTree? [I was thinking maybe make a virtual
method "get_nodes( )", which in a Tree object returns orig_nodes and in
a BuildTree object returns "build_node s", and then call get_nodes()
whenever I would normally use "nodes" in Tree methods. Would this
work?]

I don't mind refactoring my code to get this right, if anyone can
suggest a good way to redesign these objects.

Sub-question: Having two "nodes" objects with the same name in a
BuildNodes object is a really good way to shoot oneself in the foot.
(I'm surprised the code worked for so long before I found this issue
earlier today.) Is there a solution in which I can do away with this
name clash entirely?

Best,
JOSEPH

Jul 22 '05 #1
11 2100
Joseph Turian wrote:
I have a class BuildNode that inherits from class Node.

Similarly, I have a class BuildTree that inherits from class Tree.

Tree includes a member variable:
vector<Node> nodes; // For clarity, let this be "orig_nodes "

BuildTree includes a member variable:
vector<BuildNod e> nodes; // For clarity, let this be "build_node s"

So as far as I can tell, this overloads "nodes", defining two different
"nodes" variables instead of having build_nodes clobber orig_nodes (as
was my intention).
I don't think I heard the term "clobber" in relation to C++ constructs.
"Overload", "override", and "hide" is what members do to each other.
Now, let's say I have a Tree method defined:
bool Tree::is_degene rate const { return nodes.empty(); }
bool Tree::is_degene rate() const ...
If I have a BuildTree object build_tree, and I call
build_tree.is_d egenerate(), it returns "orig_nodes.emp ty()", not
"build_nodes.em pty()" as is desired.
Right...
So the question is:
Is there any way to define methods in Tree that reference "nodes", and
get those methods to act upon "build_node s" if the calling object is a
BuildTree and "orig_nodes " if the calling object is a Tree, without
duplicating the code in BuildTree? [I was thinking maybe make a virtual
method "get_nodes( )", which in a Tree object returns orig_nodes and in
a BuildTree object returns "build_node s", and then call get_nodes()
whenever I would normally use "nodes" in Tree methods. Would this
work?]
Yes, a virtual function would work. However, any time a container or the
like comes up, a template comes to my mind. So, a question to you: why
not make 'Tree' a template? Yes, you'd have to make 'Node' a template as
well.
I don't mind refactoring my code to get this right, if anyone can
suggest a good way to redesign these objects.
How are they used? Without knowing that, how can one suggest a decent
design?
Sub-question: Having two "nodes" objects with the same name in a
BuildNodes object is a really good way to shoot oneself in the foot.
(I'm surprised the code worked for so long before I found this issue
earlier today.) Is there a solution in which I can do away with this
name clash entirely?


Not sure what you mean. There is no name clash. BuildTree's 'nodes'
_hides_ Tree's 'nodes'. Inside BuildTree the base class' 'nodes' does
not exist, essentially (except that it takes up some space).

Victor
Jul 22 '05 #2
On 18 Jan 2005 10:38:19 -0800, Joseph Turian wrote:
Fellow hackers,

I have a class BuildNode that inherits from class Node.

Similarly, I have a class BuildTree that inherits from class Tree.

Tree includes a member variable:
vector<Node> nodes; // For clarity, let this be "orig_nodes "

BuildTree includes a member variable:
vector<BuildNod e> nodes; // For clarity, let this be "build_node s"

So as far as I can tell, this overloads "nodes", defining two different
"nodes" variables instead of having build_nodes clobber orig_nodes (as
was my intention).
Is there a reason why the base class can't have a vector of pointers?
vector<Node*> nodes;
would allow you to store (pointers to) objects of either Node or
BuildNode type. Of course, something like
vector< boost::shared_p tr<Node> >;
makes memory management easier.

Alternately, depending on your needs, making Tree a template class might
work for you.
Now, let's say I have a Tree method defined:
bool Tree::is_degene rate const { return nodes.empty(); }

If I have a BuildTree object build_tree, and I call
build_tree.is_d egenerate(), it returns "orig_nodes.emp ty()", not
"build_nodes.em pty()" as is desired.
That certainly sounds like it's doing what it should, according to the
standard.
So the question is:
Is there any way to define methods in Tree that reference "nodes", and
get those methods to act upon "build_node s" if the calling object is a
BuildTree and "orig_nodes " if the calling object is a Tree, without
duplicating the code in BuildTree? [I was thinking maybe make a virtual
method "get_nodes( )", which in a Tree object returns orig_nodes and in
a BuildTree object returns "build_node s", and then call get_nodes()
whenever I would normally use "nodes" in Tree methods. Would this
work?]
There are probably lots of hackish ways of getting this to work with the
two separate nodes variables. All of them are likely to cause you a
problem somewhere down the line when you (or someone else working on the
code) forget to use the workaround. Best to get the design right in the
first place, so that it does the "natural" thing.
I don't mind refactoring my code to get this right, if anyone can
suggest a good way to redesign these objects.


Without knowing more about the problem you're trying to solve, it's very
hard to give concrete suggestions. One of the two general ideas above
might work, but I can easily think of cases where neither would be
useful.

--
Greg Schmidt gr***@trawna.co m
Trawna Publications http://www.trawna.com/
Jul 22 '05 #3

"Victor Bazarov" <v.********@com Acast.net> wrote in message
news:IU******** ***********@new sread1.mlpsca01 .us.to.verio.ne t...
Joseph Turian wrote:
I have a class BuildNode that inherits from class Node.

Similarly, I have a class BuildTree that inherits from class Tree.

Tree includes a member variable:
vector<Node> nodes; // For clarity, let this be "orig_nodes "

BuildTree includes a member variable:
vector<BuildNod e> nodes; // For clarity, let this be "build_node s"

So as far as I can tell, this overloads "nodes", defining two different
"nodes" variables instead of having build_nodes clobber orig_nodes (as
was my intention).


I don't think I heard the term "clobber" in relation to C++ constructs.
"Overload", "override", and "hide" is what members do to each other.


I've seen (and been amused by) it used with C: The manual for a database
library, in descriptions of several functions warned: "Be sure you
allocate sufficient buffer space, or memory will be clobbered".
I would have probably had it say 'overwritten', but hey, I got
the message. That was probably the only software-related document
in existence that used the term 'clobber' dozens of times. :-)

-Mike
Jul 22 '05 #4
Victor,

Thank you for your reply.
I don't think I heard the term "clobber" in relation to C++ constructs. "Overload", "override", and "hide" is what members do to each other.
Yes, "override" is the term I was looking for.
Yes, a virtual function would work. However, any time a container or the like comes up, a template comes to my mind. So, a question to you: why not make 'Tree' a template? Yes, you'd have to make 'Node' a template as well.
I'm not sure, I hadn't considered that option.

The main objection is that making Tree and Node into templates is
misleading, since they aren't generic. BuildNode and BuildTree are the
only classes inheriting from them. [Perhaps this will be more clear
when I reply to your next question.]
How are they used? Without knowing that, how can one suggest a decent
design?


Without going into too much detail, I'll try to explain what I'm trying
to do:

A Tree is a decision tree that's already been constructed. The most
important operation is finding the confidence for an Example: Percolate
an Example down to a (leaf) Node, and return Node::confidenc e(). i.e.
An Example's confidence is given by the confidence of the (leaf) Node
down to which the Example percolates.

A BuildTree is a kind of Tree that implements a super-set of Tree
functionality. Essentially, it's a decision tree that's still being
built. Similarly, a BuildNode is a kind of Node that implements a
super-set of Node functionality. viz. A BuildNode includes a feature
vector, which are used to consider potential splits for this BuildNode.

Ideally, a BuildTree would include both Node objects (for internal
nodes) and BuildNode objects (for leaf nodes). Tree would only need
Nodes, since we aren't trying to split the leaves any more. (We only
need a feature vector in leaves that we are trying to split.)

Does this make sense?

Here's a slightly more involved Tree method:

/// Find the node that some example falls into.
const Node* Tree::find_leaf (const Example& e) const {
assert(!nodes.e mpty());
const Node* n = &nodes.at(root_ node);
const Node* newn;

while (!n->is_leaf()) {
if (e.has_feature( n->split())) {
newn = &nodes.at(n->pos_child()) ;
} else {
newn = &nodes.at(n->neg_child()) ;
}
assert(newn->parent() == n->id());
n = newn;
}
return n;
}
[Apologies if you don't see any indenting in the above function.]

To get the BuildTree equivalent of the above function::
s/Tree/BuildTree/g
s/Node/BuildNode/g

Best,
Joseph

Jul 22 '05 #5
Admittedly, alarm bells were ringing in my head as I typed that,
since---regardless of C++ terminology---the term "clobber" in never
used in the context of being *desired* behavior.
But I had forgotten the correct term, so I'm grateful Victor proposed
some alternatives.

Joseph

Jul 22 '05 #6
Greg,
Is there a reason why the base class can't have a vector of pointers?
vector<Node*> nodes;
would allow you to store (pointers to) objects of either Node or
BuildNode type.
That seems like it would work. Do you see any limitations to this
approach?

If I have a Node* which I know is a BuildNode* (because it's contained
in a BuildTree), then can I call a BuildNode method from this pointer
without casting the Node* to BuildNode*? (The C++ FAQ 27.10 says
pointer casts are evil, so I'm wondering if there's an alternative.)
Of course, something like
vector< boost::shared_p tr<Node> >;
makes memory management easier.


True, except that since I know that there will be only a single pointer
to each Node (in the Tree object), memory-management is not a concern.
Hence, I'd rather not incur yet another dependency for successfully
compiling my code.

Joseph

Jul 22 '05 #7
Joseph Turian wrote:
[..]
Without going into too much detail, I'll try to explain what I'm trying
to do:

[...]
Does this make sense?


What I am not sure of is why do you need two pairs of classes while you
could (or so it seems) simply have a flag in the Tree object to indicate
that it's still building and in a Node object to indicate that it still
can split...

Essentially, when all Nodes freeze, so does the tree. And you need only
one mechanism to search for nodes...

Victor
Jul 22 '05 #8
Victor,

I see no reason that this wouldn't work.
Thanks!

Joseph

Jul 22 '05 #9
On 18 Jan 2005 12:17:49 -0800, Joseph Turian wrote:
Greg,
Is there a reason why the base class can't have a vector of pointers?
vector<Node*> nodes;
would allow you to store (pointers to) objects of either Node or
BuildNode type.
That seems like it would work. Do you see any limitations to this
approach?


Well, if you wanted to make sure that BuildNodes only ever go into
BuildTrees, then you have to do some extra checking that your original
method wouldn't. For any design idea, there will always be some
pathological case where that idea doesn't work. This particular
solution isn't one where you would have to look far for such a case, but
if it works for your case, then it is a very simple method.
If I have a Node* which I know is a BuildNode* (because it's contained
in a BuildTree), then can I call a BuildNode method from this pointer
without casting the Node* to BuildNode*? (The C++ FAQ 27.10 says
pointer casts are evil, so I'm wondering if there's an alternative.)


Well, to get from a Node* to a BuildNode*, some cast will be required.
Doing it safely is what dynamic_cast is all about. If the dynamic_cast
succeeds, then you know you have a BuildNode. Otherwise, you know it's
just a normal Node.
Of course, something like
vector< boost::shared_p tr<Node> >;
makes memory management easier.


True, except that since I know that there will be only a single pointer
to each Node (in the Tree object), memory-management is not a concern.
Hence, I'd rather not incur yet another dependency for successfully
compiling my code.


Well, you still have to delete them eventually. Use of an appropriate
smart pointer class (which one is best depends on the situation, of
course) saves you that bother. Plus, you can learn how to use them now
when it's not critical, and you'll like them so much you'll never use
normal pointers again, which will save you agony eventually. I just
spent the better part of two days tracking down a bug that would never
have happened if the original author had used a reference counting
pointer class instead of a raw pointer.

--
Greg Schmidt gr***@trawna.co m
Trawna Publications http://www.trawna.com/
Jul 22 '05 #10

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

Similar topics

1
3098
by: Mohammed Mazid | last post by:
Can anyone please help me on how to move to the next and previous question? Here is a snippet of my code: Private Sub cmdNext_Click() End Sub Private Sub cmdPrevious_Click() showrecord
4
2876
by: Mohammed Mazid | last post by:
Can anyone please help me on how to move to the next and previous question? Here is a snippet of my code: Private Sub cmdNext_Click() End Sub Private Sub cmdPrevious_Click() showrecord
9
7225
by: Philip Lawatsch | last post by:
Hi, I have some questions about whats written in http://www.parashift.com/c++-faq-lite/dtors.html#faq-11.14 (Describing some memory pool) #1 From what i understand this will also work for new x and delete x, or did i misunderstand something ? and,
3
3089
by: Ekqvist Marko | last post by:
Hi, I have one Access database table including questions and answers. Now I need to give answer id automatically to questionID column. But I don't know how it is best (fastest) to do? table before rowID answID qryrow questionID datafield 1591 12 06e 06e 06e question 1593 12 06f 06f 06f question 1594 12 answer to the question 06f
4
1300
by: Frank | last post by:
Hi all, I need someone to push me in the right direction. Most of my projects at work are small tracking applications that help people generate month end production reports, i.e. (This many users did this many items between these dates). I have already developed several and they all do pretty much the same thing, log an item in and timestamp it each time someone touches it. Well I have been asked to build another one and decided I am...
7
1433
by: AMeador | last post by:
I have, at one point in time, been a pretty good programmer, but that was years ago. I can pass programming classes with and A with no problem, but writting a business class application is a bit of a struggle. I am relitively new to .NET and C#, but do have pretty strong background in computers and general programming concepts. Now to my question. I have to create an app that will pull data from a database and create a report. This report...
8
1445
by: Robert | last post by:
Hi! So far I have been doing "inheritance" in Javascript like this: ****** function TestObject(value) { this.value = value; }
3
2761
by: Ming | last post by:
I am new to php5 programming :) I redirect users to another server to login. After they login successfully, they will be redirected to test.php. The server provides xml_rpc interface so I can communicate with it. After running my scripts, I get this error: Fatal error: Call to undefined method XML_RPC_Response::kindOf() in / usr/share/PEAR/XML/RPC.php on line 1972
6
4914
semanticnotion
by: semanticnotion | last post by:
Hi sir i want to transform the data of one table into another through foreign key but the following error come to my browser Here is my code and data base structure. CREATE TABLE IF NOT EXISTS `subject` ( `subject_code` int(11) NOT NULL AUTO_INCREMENT, `Name` text, PRIMARY KEY (`subject_code`) ) ENGINE=InnoDB DEFAULT CHARSET=latin1 AUTO_INCREMENT=105 ;
0
8987
marktang
by: marktang | last post by:
ONU (Optical Network Unit) is one of the key components for providing high-speed Internet services. Its primary function is to act as an endpoint device located at the user's premises. However, people are often confused as to whether an ONU can Work As a Router. In this blog post, we’ll explore What is ONU, What Is Router, ONU & Router’s main usage, and What is the difference between ONU and Router. Let’s take a closer look ! Part I. Meaning of...
0
8826
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 effortlessly switch the default language on Windows 10 without reinstalling. I'll walk you through it. First, let's disable language synchronization. With a Microsoft account, language settings sync across devices. To prevent any complications,...
0
9534
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, it seems that the internal comparison operator "<=>" tries to promote arguments from unsigned to signed. This is as boiled down as I can make it. Here is my compilation command: g++-12 -std=c++20 -Wnarrowing bit_field.cpp Here is the code in...
0
9366
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 tapestry of website design and digital marketing. It's not merely about having a website; it's about crafting an immersive digital experience that captivates audiences and drives business growth. The Art of Business Website Design Your website is...
1
9316
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 Update option using the Control Panel or Settings app; it automatically checks for updates and installs any it finds, whether you like it or not. For most users, this new feature is actually very convenient. If you want to control the update process,...
1
6793
isladogs
by: isladogs | last post by:
The next Access Europe User Group meeting will be on Wednesday 1 May 2024 starting at 18:00 UK time (6PM UTC+1) and finishing by 19:30 (7.30PM). In this session, we are pleased to welcome a new presenter, Adolph Dupré who will be discussing some powerful techniques for using class modules. He will explain when you may want to use classes instead of User Defined Types (UDT). For example, to manage the data in unbound forms. Adolph will...
0
4597
by: TSSRALBI | last post by:
Hello I'm a network technician in training and I need your help. I am currently learning how to create and manage the different types of VPNs and I have a question about LAN-to-LAN VPNs. The last exercise I practiced was to create a LAN-to-LAN VPN between two Pfsense firewalls, by using IPSEC protocols. I succeeded, with both firewalls in the same network. But I'm wondering if it's possible to do the same thing, with 2 Pfsense firewalls...
1
3303
by: 6302768590 | last post by:
Hai team i want code for transfer the data from one system to another through IP address by using C# our system has to for every 5mins then we have to update the data what the data is updated we have to send another system
2
2777
muto222
by: muto222 | last post by:
How can i add a mobile payment intergratation into php mysql website.

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.