consider these classes (simplified)
class Character
{
public:
char name[20];
char type[20];
int strength;
};
class inventoryItem
{
public:
char name[20];
};
class weapon: public inventoryItem
{
public:
int magical resistance;
};
class spell: public inventoryItem
{
public:
int magical power;
};
i have written a class for a linked list (not allowed to use stl list)
class list
{
public:
struct listItem
{
listItem* objectPointer;
listItem* pnext;
}*phead;
list()
{
phead=NULL;
}
bool isEmpty(){
if (!phead)
return true;
else
return false;
}
void addToBack(listItem *itemtoadd)
{
listItem *ptemp;
listItem *ppast;
listItem *pNewItem;
pNewItem=new listItem();
pNewItem->objectPointer=itemtoadd;
pNewItem->pnext=NULL;
if (phead==NULL)
phead=itemtoadd;
else
{
ptemp=phead;
while(ptemp)
{
ptemp= ptemp->pnext;
}
ptemp->pnext=itemtoadd;
}
}
};
I have cut this down a lot but my question is , is there an easy way to create linked lists for all these using the same list class ? or am I wasting my time ?
every time I have tried it cant convert the pointer from type 'weapon' to type 'listitem'
I need a list of characters and a list of each weapon or spell for that character
I'm still a beginner with OOP and pointers ,
the program I have now compiles and I have a list of characters working , however the list is not managed by the class its managed within some other functions, I'm hoping there's a way for one class to deal with it all , can anyone help explain it to me ?
Take a look at C++ Templates. Using templates you can have one list class in terms of reading/writing code, but you can have a list of weapons, a list of items or a list of anything else without having to write WeaponsList, ItemsList and SomethingElseList classes separately.
The simple answer is to do this
struct listItem
{
void* objectPointer;
listItem* pnext;
}*phead;
A void pointer will allow you to store a pointer to anything. Of course it's then entirely up to you to make sure that you don't lose track of what kind of object you are pointing to. So this approach is risky. The safer approach is templates as has been suggested.
You could use:
enum item
{
WEAPON,SPELL
}
class list {
public:
struct listItem {
union {
weapon *weaponPointer;
spell *spellPointer
} object;
item objType;
listItem* pnext;
}*phead;
however the catch is you have to access the type member to determine what type of item you are accessing.
Related
I have a class which is a node of a tree, called Node. I need to create a DerivedNode class type which has some extra functionality. The problem is that Node has a vector of Node* as a member variable, so when DerivedNode inherits from Node, it inherits this vector. I've created a basic example showing the issue:
#include <iostream>
#include <vector>
class Node {
public:
Node(int value_) : value(value_) {}
int foo() { return value; }
virtual void add(Node* new_node) {
children.push_back(new_node);
}
protected:
std::vector<Node*> children;
int value;
};
class DerivedNode : public Node {
public:
DerivedNode(int value_) : Node(value_) {}
int bar() { return value*2; }
// Ensures we only add children of type DynamicNode*
virtual void add(DerivedNode* new_node) {
children.push_back(new_node);
}
void print() {
for (size_t i = 0; i < children.size(); ++i) {
std::cout << dynamic_cast<DerivedNode*>(children[i])->bar() << std::endl;
}
}
};
int main() {
DerivedNode* child_a = new DerivedNode(5);
DerivedNode* child_b = new DerivedNode(6);
DerivedNode parent(1);
parent.add(child_a);
parent.add(child_b);
parent.print();
delete child_a;
delete child_b;
}
My question is, how can I do this without the dynamic_cast? My actual code is far more complex which means that there are dynamic casts everywhere.
First add function in derived class is totally useless, it does not override add function from base class, it overloads it. In such way you still can add Node*'s to the derived class. To prevent this you should override add(Node*) as private.
If you does not like dynamic cast, you may use static cast instead
or
You may have virtual bar in base class that does not do anything
or
you can cast the vector itself (the whole thing) and assign to reference or pointer to std::vector DerivedNode*
You can't have it both ways. You either have IS-A principle reflected in the design of your classess, or you don't. If DerivedNode is Node, than the vector of Nodes should be indistinguishable from vector of DerivedNodes - and no casts are neccessary. If this can not be achieved, that you simply can not use vector of base pointers.
Any dynamic_cast in production code for me is a hard block for any review, as it clearly violates the basic design principles.
Suppose I implement my own Linked List and its nodes can hold elements of type "Car".
Within this implementation I have a method, PrintList(), which has a loop and calls the toString method for each node.
What my class looks like for reference:
template<class T>
class ArrayList {
private:
class Node {
private:
// Node accessors
T* element;
public:
// ctor's
//Accessors etc
void GetElement();
string toString();
};
//members
int size;
// etc
public:
void PrintList();
};
The node's toString() looks something like this:
string myNode::toString() {
// Returns a Car pointer.
// Still in myList implementation
// For a generic version I'ld want 'getEleemnt' or something.
return this->GetCar()->toString();
}
Car* Mylist::Node::GetCar() {
//Returns a car* ptr
return this->myCar;
//car has an implementation of toString() which is soon invoked.
}
//Inside my Car class written in some other cpp file, has no relationship
//with MyList.
string Car()::toString() {
//Car type is a set of enums defined in a header.
//Car has a EnumeratedType member field.
switch ( this->getEnumeratedType ) {
case 0:
return "I'm a veyron"
// etc
}
}
Suppose I now implement my own Linked List template. (Because as a student I find the exercise interesting and a good opportunity to practice my C++). The above toPrint() shenanigans don't work.
template <class T>
string MyList<T>::myNode::toString() {
// Returns a T* pointer.
// now in generic <T> myList implementation
//
return this->GetElement()->toString(); // this does not compile....
}
template <class T>
T* Mylist<T>::Node::GetElement() {
//Returns a element* ptr?
return this->myElement;
// This compiles iirc.
}
There does not seem to be a way to call a method on a unknown class template. Car has no relationship with myList, I could be interested in storing ANY object that isn't related to Car, suppose I wanted to Store flowers, even if they both have toString implementations, the compiler doesn't let me call them.
A possible suggestion was to create an IPrintable interface that any object I'ld intend to have be used by the generic list inherit from, but I don't know if this really solves my issue.
To summarize, I am returning a pointer, type "T", that could be Car, or could be Flowers, and I want to know if there's some way of throwing toString() darts blindly and get them to invoke their implementations.
It seems like you have implemented your own list class, so I can't comment on that. But let me explain it by using just regular stl containers. When you have a container of a specific type:
std::vector<Car> cars;
You can put in just that type:
cars.push_back(Car());
cars.push_back(User()); // ERROR
If you use polymorphism you can store different kinds of objects (that inherit from the same base-class) inside a container when using pointers:
#include <iostream>
#include <vector>
#include <memory>
class Car {
public:
virtual ~Car() {}
virtual std::string toString() const {
return "I'm a car";
}
};
class RaceCar : public Car {
public:
virtual std::string toString() const {
return "I'm a race car";
}
void raceCarSpecificMethod() const { }
};
int main() {
typedef std::shared_ptr<Car> CarPtr;
std::vector<CarPtr> cars;
cars.emplace_back(std::make_shared<Car>());
cars.emplace_back(std::make_shared<RaceCar>());
for (const auto &car : cars) {
std::cout << car->toString() << std::endl;
}
return 0;
}
However, you can NOT call methods like "raceCarSpecificMethod()" this way. If you want to call that method you would have to change the for loop to this:
for (auto &car : cars) {
std::cout << car->toString() << std::endl;
std::shared_ptr<RaceCar> race_car = std::dynamic_pointer_cast<RaceCar>(car);
if (race_car) {
race_car->raceCarSpecificMethod();
}
}
The dynamic_pointer_cast casts the Car pointer to a RaceCar pointer, making it possible for you to use the raceCarSpecificMethod. You MUST check if the returned pointer is a nullptr. If the casted pointer is NOT a RaceCar pointer a nullptr will be returned. If the above example I used shared_ptrs, when using regular pointers you should use:
RaceCar *race_car = dynamic_cast<RaceCar*>(car); // assuming that car is a Car*
I'm not sure why you are writing your own list class but in general I'd advice you to stick to std::vector.
For the implementation of linked list which is better
Using structure
#include <iostream>
using namespace std;
struct Node {
int data;
Node* next;
};
Using class
class ListNodeClass
{
private:
ItemType Info;
ListNodeClass * Next;
public:
ListNodeClass(const ItemType & Item, ListNodeClass * NextPtr = NULL):
Info(Item), Next(NextPtr)
{
};
void GetInfo(ItemType & TheInfo) const;
friend class ListClass;
};
typedef ListNodeClass * ListNodePtr;
Or is their any better way for doing linked list in C++ ?
The only one thing which class and struct makes differ in C++ is the default interface. if you write:
struct MyStruct
{
int a;
}
and:
class MyClass
{
int a;
}
the only one difference is a field in both them. In MyStruct field a is public and in MyClass field a is private. Of course you can manipulate them using public and private keywords in structs and classes both.
If you are programming in C++ you should use classes.
A linked list is one thing, its nodes are another thing. The nodes are part of the implementation of the list. They should not be visible in the interface of a list so their form doesn't really matter. I would do this
class List
{
private:
struct Node
{
int data;
Node* next;
};
public:
...
};
I have seen lots of codes to implement BST(online and in some books).Most of those code have a struct like below:-
struct node{
int data;
struct node *left;
struct node *right;
};
class tree{
private:
node *root;
public:
//other helper function like insert,delete,display
};
But if i want to use OOPS in much better way then would it be correct to say that i should create class node{}; instead of using struct ???
I have written code below , which according to me is uses OOPS concept in much better way.
please suggest me any changes if you find and problem with the design:-
my code :-
#include<iostream>
using namespace std;
class node{
private:
int data;
node *left;
node *right;
public:
node()
{
data=0;
left=NULL;
right=NULL;
}
node(int val)
{
data=val;
left=NULL;
right=NULL;
}
int getData()
{
return data;
}
node* getLeft()
{
return left;
}
node* getRight()
{
return right;
}
void setData(int val)
{
data=val;
}
void setLeft(node *l)
{
left=l;
}
void setRight(node *r)
{
right=r;
}
};
class tree{
private:
node *root;
node *insertHelper(node*,int);
void inorderHelper(node*);
public:
tree()
{
root=NULL;
}
void insert(int val)
{
if(root==NULL)
{
root=new node(val);
return;
}
insertHelper(root,val);
}
void inorder();
};
node *tree::insertHelper(node *root,int val)
{
if(root==NULL)
{
root=new node(val);
return root;
}
else
{
if(root->getData() > val)
{
root->setLeft(insertHelper(root->getLeft(),val));
}
else
{
root->setRight(insertHelper(root->getRight(),val));
}
}
}
void tree::inorder()
{
if(root)
{
inorderHelper(root);
}
}
void tree::inorderHelper(node *temp)
{
if(temp!=NULL)
{
inorderHelper(temp->getLeft());
cout<<temp->getData()<<" ";
inorderHelper(temp->getRight());
}
}
By creating class node{} and keeping left ,right,data as private member , am i doing too much and making things complicated or it is a good approach???
BSTs, while in some ways very complicated, are really very simple. What you're doing - setting everything private unless it absolutely needs to be otherwise - is good OOP convention, but isn't really necessary here. You have a single class - that means inheritance and polymorphism are irrelevant - which is used for basically a single, very straightforward purpose, which means that restricting access doesn't really do much (it's very improbable that your code will be used by someone else who decides to arbitrarily mess with fields that shouldn't be messed with).
You aren't losing any functionality by making your struct a class, but you aren't really gaining any, either. If, later on, you have even the hint of a plan to somehow use a modified BST of some sort, by all means use classes, because then inheritance will become relevant; but if not, there isn't much of a difference between class and struct, other than style.
Generally speaking, if the construct you are going to make is only holding data (and does not need to change or access the data directly), then you do not need a class. This is why, with a BST, a struct will suffice for the node when there is already a Tree class.
Why would a struct for the node suffice, though? Well, that comes down to the fact that you don't need to have the methods that you have provided in your "node" class for two reasons. Firstly, anything that the methods you have in your node class are accomplishing is somewhat unnecessary; the Tree class is already responsible for traversing the BST, adding new nodes, deleting unwanted nodes, and obtaining data (you typically do not want to have mutator functions that will change the values stored in the nodes after they have been added as this could result in a BST that does not adhere to the structure required for a BST). Secondly, as stated above, the node only needs to hold data. This introduces an important paradigm in C++ which is one of the key differences that sets it apart from other languages that have objects: it allows us to only make classes when they are absolutely necessary (in Java, for example, everything is a class!). Accordingly, we should take advantage of this and use structs when a class is not required. In my experience, having fewer classes will result in code that is easier to write and for others to understand.
Regarding making the member variables of the node struct private in the class you have defined: This is a good idea for data encapsulation and can prevent mishaps, but just try to be careful when you are programming the BST and you should be okay!
Hope this helps and good luck programming :)
I have a class that contains some data: class DATA
Now I would to create some functions that uses those data. I can do it easily by writing member functions like DATA::usedata();
Since there are hundreds of functions, I would to keep an order in my code, so I would like to have some "categories" (not sure of the correct name) like:
DATA data;
data.memory.free();
data.memory.allocate();
data.file.import();
data.whatever.foo();
where memory, file and whatever are the "categories" and free, allocate and foo are the functions.
I tried the inheritance way, but I got lost since I can not declare inside DATA a memory or file object, error C2079 occurs: http://msdn.microsoft.com/en-us/library/9ekhdcxs%28VS.80%29.aspx
Since I am not a programmer please don't be too complicated and if you have an easier way I am all ears.
Give your data class some classes of its own, and let those classes refer to the data object that holds them. It sounds like you might have tried to do that already. If you got an error, then you were doing something else wrong.
struct DATA
{
struct DataMemory
{
DATA& data;
DataMemory(DATA& d): data(d) { }
void free();
void allocate();
};
struct DataFile
{
DATA& data;
DataFile(DATA& d): data(d) { }
void import();
};
struct DataWhatever
{
DATA& data;
DataWhatever(DATA& d): data(d) { }
void foo();
};
DataMemory memory;
DataFile file;
DataWhatever whatever;
DATA(): memory(*this), file(*this), whatever(*this) { }
};
Each of the inner classes has a member that's a reference to the containing DATA object. They have constructors to allow that member to get assigned. The DATA class itself also has a constructor to initialize each of its members with a reference to itself.
You can now implement the functions and refer to any of the DATA object's members.
void DATA::DataMemory::free()
{
data.whatever.foo();
}
The inner classes aren't required to be inner classes; they could be standalone top-level classes like DATA if you want, but I think nesting them helps show their interdependence.
The easiest way would be to do the categories just as a naming convention. If you replace the . with _ you don't need any "subobjects" and get:
data.memory_free();
data.memory_allocate();
data.file_import();
This way you basically have the same function names but avoid all the implementation problems of the subobject approach.
If you have a class that has hundreds of member functions, you almost certainly need to break that up into multiple classes. To achieve the type of naming syntax that you're after you could use name spaces to group related classes into "categories."
class DATA
{
public:
class CategoryA_Class
{
friend DATA;
private:
CategoryA_Class() { }
public:
bool GiveMeSomeInt() { return 1; }
};
class CategoryB_Class
{
friend DATA;
private:
CategoryB_Class() { }
public:
bool GiveMeSomeBool() { return true; }
};
public:
CategoryA_Class CategoryA;
CategoryB_Class CategoryB;
};
int _tmain(int argc, _TCHAR* argv[])
{
DATA mydata;
int a = mydata.CategoryA.GiveMeSomeInt();
bool b = mydata.CategoryB.GiveMeSomeBool();
return 0;
}
It is normal to feel confuse when you have so many functions in one class. The trick is to break it all up so that the information is contained in smaller classes that inherits a parent class that has common functions and data to all children.
From what I see you already found a common name for the information. class DATA can be that parent class. Now, you need to break up the information into types of Data. In other words, you will have children classes that will be specialized in something. A quick way to divide the information is to create a diagram of a parent class linked with children classes.
Here is a small example of what you could do:
//parent class
template <class T> class Data
{
T data_; //you could use an array like a std::vector or
//use a stream
public:
//...
void foo();
T getData() const;
};
//child class
template <class T> class Memory
: public Data
{
public:
void free();
void allocate(T data);
//...
};
//child class
template <class T> class File
: public Data
{
public:
T readFile(); //could read the contents of a
//file and save it in data_ (class member from parent class)
void writeFile(); //could write data_
//(class member from parent class) to a file
//...
};
Also, here is documentation if you need help on the concept of inheritance.