Recently, I am learning Inheritance and Polymorphism in C++.
I made three classes: Node, uni_dir_Node(uni-direction Node), and bi_dir_Node(bi-direction Node).
Here is my code:
class Node {
protected:
string name;
Node* next;
virtual void connect(Node* _Node) = 0;
};
class uni_dir_Node : public Node {
void connect(Node* _Node) {
this->next = next;
}
};
class bi_dir_Node : public Node {
Node* previous;
void connect(Node* next_Node, Node* previous_Node) {
this->next = next;
this->previous = previous_Node;
}
};
int main()
{
Node* head = new bi_dir_Node;
return 0;
}
Of course there is a compiler error in this code.
My question is, the function connect() in class uni_dir_Node has one parameter but for the function connect() in class bi_dir_Node has two parameters. How do I keep this inheritance structure and make it legal?
Is there any good way to solve this problem?
As others have said, the problem is that bi_dir_Node doesn't have a void connect(Node* _Node) method.
Conceptually, what's going on is that inheritance indicates an "is a" relationship. Saying that bi_dir_Node inherits from Node means that bi_dir_Node is a Node, so anything that a Node can do, a bi_dir_Node can do.
You're trying to say that bi_dir_Node is a Node but that it can't do everything a Node can: specifically, it can't Connect with a single argument.
The solution is to either provide a single-argument Connect for bi_dir_Node or to remove or redesign the inheritance structure. For example, in C++, templates may be a better approach: you can make uni_dir_Node and bi_dir_Node completely separate (not part of the same inheritance hierarchy) and write template classes and template functions that are generic enough to operate on both.
As says nwp, to have polymorphism, you need to have functions with the same prototypes in the derived classes.
By prototype, it means :
same return type
Same parameter list
const keyword at the end of the prototype must be present on derived if present on base method
same method name of course
This is because all functions need to be called the same way and same semantic whether it is a base or derived object.
virtual key word must be put on the base class method prototype.
The virtual behavior is inherited. So it can be put or not on derived class overriden methods.
Advanced stuff - not often useful :
Since C++ 98 (prehistory !), if a base class method is
Base * Method();
The derived method can be :
Derived * Method();
This is because Derived* IS A KIND of Base*
Hope it clarifies
Related
Say I have an object Node, which has a function addPath() that expects another Node as an argument.
virtual void Node::addPath(Node * otherNode)
{
// does something with otherNode
}
Now, say I derive from Node. Let's call this DerivedNode, and it has a new function foo(). I want to override the addPath method. I also know when I call DerivedNode::addPath, the parameter would always be another DerivedNode. Meaning I want to be able to call foo() inside the addPath() method.
int DerivedNode::foo();
void DerivedNode::addPath(Node * otherNode)
{
int x = foo(); // no problem
int y = otherNode->foo() // BAD! otherNode is typed as Node, not DerivedNode
}
I can't call otherNode->foo(). What should I do?
Obviously I know I can cast, but that seems like a clunky rookie solution. Do we have anything more elegant? I feel like this should be a fairly common use case.
you have to cast, unless you set something like this in your base class. but all derived classes need to implement it, depends on your program.
virtual int foo() = 0;
You cannot call 'foo' method because is not a member of base Node. Indeed you could to a cast but make sure that type of node argument is indeed a DerivedNode otherwise your will get an exception.
Yes, you could call x = foo() method from addPath method because you are making calls from DerivedNode class.
Or you could define foo() as virtual method in your base class. Either make it abstract but in this case you will not be able to create an Node instance or you could provide a default/empty implementation.
Let's assume your Node class is an abstract class for 2 types of nodes:
you're gonna have your leaf nodes, that perform some functionality
you're gonna have your composite nodes, that will store other nodes
In this context, 2 questions arise:
Why does the base class have the 'addNode' method? Leaf nodes won't have any use for it...
What does foo() do? Perhaps adding 'addNode' to the base class, and then making 'foo()' into a template method would be a good approach.
Once you answer those, you will get a clearer picture of the responsibilities those methods hold - and that in turn will give you a hint where (in which class) to put them.
If only one of your derived classes needs a foo() operation, then you should use a dynamic cast (or reconsider your design).
If the "foo" operation is one that applies to more than one derived class, then you should add a virtual method foo() to your base class(Node).
If (almost) every derived class needs some type of foo operation, then make the foo() method abstract (pure.)
If many of the derived classes don't need a foo() operation then make it be a "no-operation" in the base class so derived classes that do NOT need to foo() can simply ignore the issue.
The code below uses this technique.
class Node
{
virtual void Node::addPath(Node * otherNode)
{
// does something with otherNode
}
virtual void foo()
{
// nothing to do in the base class
}
};
class DerivedNode : public Node
{
void DerivedNode::addPath(Node * otherNode)
{
int x = foo(); // no problem
int y = otherNode->foo(); // Now this works.
}
void foo()
{
// this is the DervivedNode-specific foo!
Node::foo(); // just in case the base class has an opinion
do my foo-ish stuff here;
}
};
I have a class like this:
class A {
protected:
class Node {
public:
int x;
Node* next;
};
Node* root;
.
.
.
};
And a lot of methods using this "root".
Now, say I want to inherit from A class, and make all the methods use a "better" node. Something like:
class B : public A{
class NewNode : public A::Node{
public:
int y;
};
NewNode* root;
.
.
.
};
Is there a way of doing something like this? And if not, what are the alternatives (beside rewriting A class)?
Thank you!
Since NewNode is derived from Node you can put something like this in the B constructor
delete root; //remove the Node
root = new NewNode(); //and put in the better one
More realistically, you'll probably need something like this
Node * oldRoot = root;
root = new NewNode(oldRoot);
delete oldRoot;
You don't need a new variable in B, just use A::root.
If A is abstract, it can be compiled and used with all its methods independently from any derived classes. Therefore, code that accesses this variable will already be generated and cannot change. I think there is really no way to do what you want to do, without modifying A.
Although, it depends a little bit, what exactly you mean. If NewNode is derived from Node and Node has virtual functions, A will of course call the methods of NewNode. If you don't want NewNode to be derived from Node, you probably have to make A a template class. This would also work, if A accesses members of Node directly, instead of using virtual Getter/Setter-Functions.
I have a skeleton of a project I need to implement a Doubly Linked List (no using stl) and the way the class is implemented is to inherit all is methods from a struct like so:
struct IDoubleList {
virtual IDoubleNode * getHead() = 0;
virtual IDoubleNode * getTail() = 0;
virtual void setHead(IDoubleNode * head) = 0;
virtual void setTail(IDoubleNode * tail) = 0;
virtual void addBack(int value) = 0;
};
class DoubleList : public IDoubleList {
public:
virtual IDoubleNode * getHead();
virtual IDoubleNode * getTail();
virtual void addBack(int value);
virtual void setHead(IDoubleNode * head);
virtual void setTail(IDoubleNode * tail);
private:
DoubleNode* m_Head;
DoubleNode* m_Tail;
};
As you can getters and setters use the struct, not the class to return/pass pointers. My question is how can I use the methods in he object m_Tail is pointing to. I tried using m_Tail.setNext(newNode); where setNext is method in the DoubleNode class but that says the expression must have a class type.
Also when I return/pass a DoubleNode* should I be casting or something to IDoubleNode*? or maybe its the other way around?
PS been a while since ive used C/C++, maybe I'm forgetting something about function pointers? idk so lost right now
Thanks in advanced, let me know if you need any more info
First of all, it should be m_Tail->setNext(newNode), not m_Tail.setNext(newNode) because m_Tail is a pointer. You could also do (*m_Tail).setNext(newNode), the point is that you have to dereference the pointer somehow.
No, you do not need to cast a pointer from a DoubleList to IDoubleList when passing it to a function expecting an IDoubleList. This is because every DoubleList is a IDoubleList, so no casting is required. Also, the only difference between a struct and a class is the default access level of the members (public for a struct, private for a class).
First, you should make IDoubleNode a base class of your DoubleNode (if you haven't already). Then you need to dynamic_cast<DoubleNode*>(ptr) in the methods taking a IDoubleNode* to get hold of your DoubleNode (and e.g. throw an exception if this fails). Also, make sure you use pointer notation when accessing members of pointers, i.e. ptr->member instead of ptr.member: the latter notation only works for objects. You could use (*ptr).member but this is unnecessarily contrived.
Finally, don't forget to tell your instructor to set reasonable assignments next time because this is an entirely pointless exercise: this is bad example for using object oriented approaches (you can subvert type-safety via the base class interface) and it is pointless to use object oriented approaches in a data structures class.
here are the classes which my question is about
class Graph {}
class SceneGraph : public Graph {}
class Node {
public:
virtual Node* getNode(int index) { return mNodeList[index]; }
protected:
vector<Node*> mNodeList;
Graph* mGraph;
}
class TransformationNode : public Node {
public:
TransformationNode* getNode(int index) { return static_cast<TransformationNode*> (mNodelist[index]); }
void _update() {
auto beg = mNodeList.begin();
auto end = mNodeList.end();
while (begin != end) {
TransformationNode* node = static_cast<TransformationNode*> (*beg);
node->_update();
}
}
private:
bool mUpdated;
SceneGraph* mGraph;
}
First of all, I want to talk about the problems I solved. They may helps others. And you can confirm me if I am right ^^
Can I override a function with a different return type ?
Node* getNode(int index) became TransformationNode* getNode(int index)
Yes as long as return types are covariant : http://www.tolchz.net/?p=33
Can I override a member ?
I don't know about overriding but a variable with the same name in the derived class will hide the one in the base class
And there is the problem I really want to get around some how
In the TransformationNode class I did many (IMHO) avoidable type casting from base class to derived one. I definitely know that all the elements in the mNodeList vector are TransformationNodes but to process mNodeList I have to type cast them.
The inheritance is correct I mean TransformationNode is a Node
mNodeList holds child nodes of the node and it can not have a copy in the derived class which holds typecasted version of Nodes
And finaly I can even use reinterpered_cast if static_cast is more costly. Can you inform me about cost of these operations ? are they really big performance issues ?
assert (dynamic_cast)... kind of precaution has already been taken.
briefly I want my compiler to know that mGraph is actually a SceneGraph* and mNodeList holds TransformationNode* this helps me to avoid lost of type casting.
Thank you for taking your time
1) is correct, you can indeed override (virtual!) base functions if the return type is more derived.
Ad 2): indeed, you cannot "override" members. Redesign the base class if you need more flexible overridable behaviour.
static_cast is a static operation that is resolved at compile time, so much like reinterpret_cast it doesn't have any "cost".
As #Seth suggests in the comment, it might be an option to move the container. Ask yourself, can there ever be an abstract Node, or is every node actually of some derived concrete type? Perhaps you could make Node abstract:
struct Node { Node * getNode(size_t index) const = 0; };
struct TransformNode : Node
{
TransformNode * getNode(size_t index) const { return m_nodes[index]; }
private:
std::vector<TransformNode *> m_nodes;
};
Put the entire interface into the base class, but only implement it in each concrete class.
I have a C++ inheritance related question. I have a set of classes like this (I have not given the complete class structure coz I am lazy :) ). I want to access chiComponent class public methods using com pointer. How should I go about it?
Note that I am having to change the object which "com" is pointing to in a lot of places.
So I do not think I can have another
chiComponent *ccom = <some_cast> com;
ccom.chiComponentMethod()
How should I go about it?
class Component{
};
class chiComponent : public Component {
public:
void chiComponentMethod()
{
cout << "Hi! Chi component function called!!";
}
}
class parent {
protected:
Component *com;
};
class child : public parent{
public:
child() {
com = new chiComponent();
}
}
Regards
Arun
You will need to implement a pure virtual method in Component; say, componentMethod():
virtual void componentMethod() = 0;
This will make Component an abstract class, and thus uninstantiable.
Then in chiComponent you can have:
virtual void componentMethod() {
chiComponentMethod();
}
Alternatively, you could just rename chiComponentMethod to componentMethod and put the implementation in there directly.
Additionally, any further implementations of Component can implement their own functionality.
Also, I believe that
com = new chiComponent();
should be
*com = new chiComponent();
since com is a Component *.
AVL tree is a type of a BST tree in the sense, that it supports all the BST tree operations and additionally may provide some more. So at the first glance it makes sense to derive AVLTree form the BSTTree. But BSTTree relies on an inner class BSTNode, that is not sufficient for providing all the AVLTree functionality.
If You derive AVLNode from BSTNode there are two options. You could change the BSTNode to support all the functionality the superclass needs, but it doesn't make much sense. It's way better to just design the node class, that supports all the functionality for both types of tries, from the very beginning.
The other option is to make all the BSTTree public methods virtual and explicitly cast the node to AVLNode in all implementations of those methods for the AVLTree class. You want to make those methods virtual anyway. Otherwise if someone is using a BSTTree interface to manipulate an actual instance of an AVLTree (having for example a BSTTree* pointer pointing to an AVLTree instance) disasters are going to happen.
Use virtual functions in the base class:
virtual void chiComponentMethod() = 0;
Easiest way is to make virtual functions in Component and chiComponent, then always use the Component *com base class pointer.
May be I will explain the problem more accurately.
I am trying to code AVL trees in C++ and I am extending AVL class from BST (Binary Search Tree) class. I also have two more classes
class BSTNode {
protected:
int data;
class BSTNode *left, *right;
};
class AVLNode : public BSTNode{
int height;
};
BST class uses BSTNode and AVL class uses AVLNode.
I am using BST class services for things like inorder traversal etc.
For insertion and deletion I am using AVL class functions (through virtual functions).
For obvious reasons I am having a
BSTNode *root in BST class. The root changes whenever I do insert, delete etc.
In AVL class is there any easy way to change **root'**s type to a more specific and more meaningful AVLNode type?