I'm currently having an assignment, in which i need to create a DATABASE class,
which contains a employees pointers array, and private inner class,
that defines employees linked list
the goal to accomplish here, according to the assignment, is working acording
to a DB_TYPE defined constant.
when DB_TYPE = 0 i need my class methods to work with the employees pointers array,
when DB_TYPE = 1 i need my class methods to work with the employees linked list.
Therefore, i need two things:
1. Understanding constructor calling -
When i construct a new DATABASE object, for example with no paramaters,
the default constructor is called.
How do i call the linked list inner constructor to construct a Node, from the constructor itself?
2. Working according to the DB_TYPE constant -
I Suppose that's less of a trouble, as i can set my methods to work with
two cases\or with 'if' conditions regarding each value of DB_TYPE.
but if that's not that simple, i'll be glad to get some advise\help on how to do so.
EDIT:
My Current code:
class DataBase {
public:
DataBase();
private:
Employee ** empArr; /*!< Employees pointers array */
unsigned int empCount;
Node head;
class Node{
public:
Node();
Node(Employee * emp, Node * next);
private:
Employee * emp; /*!< Employee Pointer */
Node * next; /*!< The next node (containing the next employee) */
};
};
Thanks,
Adiel
The Node node; has to come after the definition of class Node.
To invoke a non-default constructor of node when creating a Database you use the constructor initialization list:
Database::Database()
: head(foo, bar)
, empCount(0)
, empArr(nullptr)
{
}
You can and should initialize the other members in this list too. If the object needs complicated initialization you can write a function to do that; initializing via the constructor body should be a last resort. (well, a later resort, it's not a terrible thing).
Note that the order member objects are initialized is the order they appear in the class definition - not the order they appear in the constructor init list. So if, for example, your head's constructor argument had to be worked out from empArr, you would have to make sure that Node head; came after Employee **empArr;, and also you'd have to write a function to set up empArr so your list would look like
: empCount(5), empArr( allocate_emparr(5) ), head(empArr[0], nullptr)
Re. DB_TYPE. Since it is preprocessor you can do, wherever appropriate,
#if DB_TYPE
// code for processing linked list
#else
// code for processing pointers array
#endif
This is very powerful, although some people consider it ugly. It's be nicer to use a template instead, especially if the class definition can stay the same and it is only a small number of functions whose behaviour needs to change. However it is challenging to write the template version well if you have not used templates much before.
Example declarations (could be class members or free functions):
template<int N> void do_something(void);
template<> void do_something<0>(void) { /* process pointers array */ }
template<> void do_something<1>(void) { /* process linked list */ }
Usage:
void other_func(void)
{
do_something<DB_TYPE>();
}
Related
So I am in process of coding class for some graph structure (suffix tree), and I encountered this difficult thing: a node should have pointers, one pointing on its parent, and also a set of pointers to its sons. I am using smart pointers to avoid errors with memory, and here is the thing: I write
class node {
...
std::shared_ptr<node> parent;
...
};
I guess there is a term for this thing. Like self-referencing, or whatever. When I wrote it, initialy i was confident, that there will be an error, but no it had been successfully compiled. I was curious, can i write something like that:
class some_class_2{
...
std::vector<some_class_2> some_vector;
std::string string_;
some_class() {
string_ = "lol";
some_vector = std::vector<some_class>(10);
}
};
Its appeared that the answer on this question is yes. So when i launched the test programm which had been succesfully compiled, of course it wouldn't stop, maybe i waited not enough and it should throw me some memory related error.
So the question is, how you should handle with this kind of things in c++? Isn't it strange that those things allowed in c++? Is it normal to put std::shatre_ptr inside some_class? How to write safe code, where errors like in some_class_2 are avoided, and what is the best way to
represent graph structure?
If the language did not allow any use of node inside the definition of node, then there would be no way to create linked data structures such as lists and trees. In order for the language to be useful, it has to allow such constructs as:
struct node {
int key;
node* next;
};
On the other hand, the language cannot allow this:
struct node {
int key;
node next;
};
because then a node object would contain an infinite nested sequence of node objects and be infinitely large.
The way the language deals with this is to allow members of classes only to be complete types. A complete type's size is known. A class type is not complete until its full definition has been seen. So node is not complete inside its own definition, so you cannot put a node member inside a node object. But node* is complete even when node is not complete yet.
Some standard library templates can be used with complete types. The smart pointers, std::unique_ptr<T>, std::shared_ptr<T>, and std::weak_ptr<T>, are allowed to have incomplete T, since they have pointer semantics. However, std::vector does not allow its template parameter to be incomplete, and the result is undefined behaviour. The way to avoid this is to just not write it (it's not that hard).
I am working on Michael J Laszlo's Book 'Computation Geometry and Computer Graphics in C++' .
The following is a template class prototype:
template <class T> class ListNode : public Node {
T _val;
ListNode (T val);
friend class List<T>;
};
template <class T> ListNode <T>::ListNode(T val)
{_val=val;};
template <class T> class List{
private:
ListNode <T> *header;
ListNode <T> *win;
int _length;
public:
List(void);
~List(void);
T insert(T);
T append(T);
List * append(List*);
T prepend(T);
T remove(void);
void val(T); // overloaded function!
T val(void);// overloaded function!
T next(void);
T prev(void);
T first(void);
T last(void);
int length(void);
bool isFirst(void);
bool isLast(void);
bool isHead(void);
};
Now look at the way he defines the List constructor:
// constructors and destructors
template <class T> list<T>:: List(void): _length(0)
{
header =new ListNode<T>(NULL);
win=header;
}
My Question:
What is up with the assigning a default length outside the {...} and the rest inside? Is there some sort of logical reasoning behind this?
Because for example before this, he pretty much declared everything outside the {...} and I assumed that was just his style
What is up with the assigning a default length outside the parenthesis and the rest inside the curly braces?
This is very common and desirable. The construct is called initialization list. For example, this
template <class T> ListNode <T>::ListNode(T val)
{_val=val;};
can be rewritten as this:
template <class T> ListNode <T>::ListNode(T val)
: _val(val) {};
Using this construct instructs the compiler to use copy constructors for items being copied, rather than using default constructors followed by assignment operators. In case of assigning primitives it hardly matters, but with more complex types initialization lists could save you some CPU cycles.
The reason the author did not put the header and win assignments into the initialization list is to force a particular order of initialization where it matters. The assignment to header must happen before the assignment to win. When you use initialization lists, the order of assignments is not controlled by the order of items in the list: instead, it is controlled by the relative order of declaration of the corresponding members in the class. Relying upon it is very confusing to the reader and too fragile to remain in production, so the author correctly decided to move the two assignments into the body of the constructor.
The way I'm reading the question, you're not asking why _length is initialised in the initialiser list, but you're asking why header and win aren't.
Suppose you had
template <class T> List<T>::List(void)
: _length(0)
, header(new ListNode<T>(NULL))
, win(header)
{ }
What would this do? Would this initialise header and then copy it to win, or would this first copy header to win and only then set header? You cannot tell by looking at the constructor definition. You can tell by looking at the constructor definition when plain old assignments are used. So some (myself included) might say the code is easier to read the way it is.
It is for efficiency reason. That region -- before the {} and after the () is called initializer list. You can initialize your variable there. The compiler instead of default initializing your member variables will initialize the variables set in that initializer list.
Compare it to the scenerio where you initialize your variable inside the {}. The compiler first initializes all your member variable then goes into the body, {}, then you re-initialize your member variables. The initializer skips that initialization step. Always initialize in the initializer-list when possible.
Firstly, it is more efficient to define values in the initialiser list. If you don't do this, unless you have a clever compiler, the values will be default initialised, and the assigned to. For some types, this is not terribly efficient (although not in the class you have there).
As to why he decided to do it this way for this one class, it's unclear. I can only assume it is so that he can perhaps catch the possible throw from the new in an out of memory situation - although even there he could do a new(nothrow) for that which would probably be both more efficient and clearer.
What he could be trying to do is not to fall foul off the order of initialisation requirements of C++ - class members are initialised in the order they are declared in the class definition, not in the order you specify them in the constructor initialisation list. That can be a real pain, though most compilers now warn you if you are doing that (and also allow you to change that warning into an error). In this case, it would be possible for win to have been declared before header, in which case doing win(header) in the initialiser list would set win to have the value of header, before header got initialised. Although, even there, I'd still have initialised header in the initialiser list, and only put the initialisation of win in the code block.
What really irks me is his use of (void) parameter lists. That's a C-ism, and looks ugly. Especially for default constructors and destructors.
I have a class
class PCB {
public:
struct {
string type;
**linklist list;**//refer to list which contains PCB instance
} status;
}
what i want is to create the class PCB instance, but the instance is in a linklist list. i build the linklist class as below
class linklist
{
public:
void append( PCB num );
};
void linklist::append(PCB num){
}
Error occus saying num above is in error type. what shall i do in this case?
If you do not need the copy in your linklist::append method you could as well just use a (const) reference
void append(const PCB& num);
and forward declare PCB before in the same header file
class PCB;
You could do a forward declaration on one of the types but your really should ask yourself why you are doing this.
I cannot think of any time when this would be a good idea. If you think about your problem relative to the real world linklist is a collection of buckets. What you are asking for is a bucket (PCB) to hold a series (linklist) of buckets (PCB). In reality this would never work as a bucket cannot hold a collection of other buckets of the same size.
Another think to ask yourself, why would you use a link list when the STL (Standard Template Library) provides everything you would need and more already. I would highly recommend a vector if you list of PCB's are fairly static, or a list if not.
Linked lists can be very efficient for lightweight containers but you have to maintain them. If you using classes, GO WITH STL containers.
You can use forward declaration:
class linklist; // forward declaration
class PCB {
public:
struct {
string type;
linklist list; //refer to list which contains PCB instance
} status;
}
Or when you only refer to a type by reference or by pointer, you do not need to include it's header file.
linklist* list
You need to forward-declare each class before defining the other. In the header that defines PCB, write
class linklist;
before the definition of PCB, and in the header that defines linklist, write
class PCB;
before the definition of linklist. That way, when the compiler encounters each of the class definitions, it'll know that the "other" class's name is valid and let you declare pointers to it even though it hasn't been fully defined yet.
Edit: Sorry, I just noticed that your linklist::append function actually takes a PCB instance, not a pointer. In that case you need to make sure that the PCB class is defined before linklist, but you still need to forward-declare linklist before PCB so that you can make pointers to it. The order of your code should be:
class linklist;
class PCB {
// involves pointers to linklist
;
class linklist {
// holds instances of PCB
};
Edit Again: I's misread your **linklist list as a pointer to a linklist (even though it's syntactically wrong).
What you need to do is:
Forward-declare PCB so that the definition of linklist can refer to it in a method signature.
Define the linklist class, but not its append function yet.
Define the PCB class, which can contain an instance of linklist since that class is now fully-defined.
Define the linklist::append() function, which can take an instance of PCB since that class is now fully-defined.
That'll get your code to compile, but it won't do what you probably want it to, because the way you've defined your classes doesn't make much sense. Your PCB class doesn't "refer" to a list, it contains a list within it. Since that list member variable isn't a pointer, every PCB instance contains an entire linklist. When you append() a PCB to a linklist, you're making a copy of that whole PCB, including the (different) linklist that it contains.
I have a feeling you're coming from Java or C# and you're assuming that things are references when they really aren't. You need to learn about how to use pointers.
I have C# background and been working with C# for so many years.. Recently, I'm learning C++ and having some difficulties..
Basically, I'm trying to create the linked link class as below. I want to use my class as a data in struct node.
How can I fix this in C++? Thanks.
But it said that i can't use like that.
class Polynomial{
public:
Polynomial(pair<double, int>);
void add(Polynomial);
Polynomial multiply(Polynomial);
void print();
private:
struct node
{
Polynomial data;
node *link;
}*p;
};
Your node struct contains a member variable of type Polynominal, but since node itself is declared inside Polynominal, the declaration of Polynominal isn't complete at that point.
I get the impression that you assume classes in C++ to work just like C#, but they don't. C++ isn't garbage-collected, and it doesn't automatically manage references for you when you use classes. A class in C++ behaves more like a struct in C#, and when you pass or declare it like in your example, it gets copied by value.
Another thing: C++ comes with STL, which contains a range of templates for all sorts of things, including a nice linked list (std::list).
Couple of issues:
Polynomial doesn't have a default constructor, so the only way to create it is by using that custom constructor you have. However, your inner struct contains an object of type Polynomial. How is that supposed to be created? You can't embed objects that don't have a default constructor in classes unless you initialize them specifically in the container's constructor.
Your struct contains an object of the type of the parent class, which you're still in the process of defining! If anything, you need to make that struct its own class.
In general, you seem to do a lot by-value operations. This is very inefficient - you should always pass Polynomial by reference or pointer.
To fix it just use Polynomial &data; instead of Polynomial data; in the struct
Change that to Polynomial *data; and it will work just fine. And therein lies your clue as to what's wrong. Understanding that will bring great enlightenment.
One way of explaining it is that in C++ (unlike C#) a Polynomial and a float behave in exactly the same way with regards to how storage is allocated with them. In C# you can't do new float; (not to be confused with new Float();) and in C++ you can.
The points raised by EboMike are all valid, but just to make it compile (it's still unusable due to the constructability issue):
class Polynomial{
public:
Polynomial(pair<double, int>);
void add(Polynomial);
Polynomial multiply(Polynomial);
void print();
private:
struct node; // forward declaration creates incomplete type
node *p; // OK to have pointer to incomplete type
};
struct Polynomial::node
{
Polynomial data; // class Polynomial is complete now
node *link;
};
I wanted to make a linked list class ListList that inherits from a class List.
ListList uses functions from List, but has its own functions. It has its own start pointer that points to the beginning of the list, and its own Node struct that holds a different amount of elements.
But, it looks like, when one of List's functions are called from ListList, List uses it's own start pointer and Node. But I want ListList's start pointer and Node to be used.
Can someone help me figure this out?
I could post some code, but I don't know what part would be relevant...
this is the one I called List above
class LinkList
{
public:
LinkList(); //constructor that sets the start pointer to NULL, to show that the list is empty
~LinkList(); //destructor that deletes each node in the linked list
LinkList(const LinkList &original); //copy constructor
void addToken(string token); //creates a node with the given token and places it at the beginning of the linked list
string showList(); //returns a string of tokens, separated by commas and spaces
bool findToken(string token); //searches linked list for the given token, returns true if the token is in the list
string getToken(string word); //searches linked list for a token that begins with the given word.
//Returns the full token if there's a token that begins with the given word, else returns an empty string
void deleteList();
protected:
struct Node //each node of the linked list, held together by the next pointer
{
string token;
bool second_word; //tells whether or not there is a space within the token (a two-word keyword)
//This could be easily changed to an int that tells how many words are within the keyword (for multi-word keywords)
Node *next; //pointer to the next node of the linked list. NULL if there is no next node
};
Node *start; //pointer to the beginning of the linked list, and the last added node
bool twoWordToken(string token); //returns true if there is a space located within a token, meaning the token consists of two words.
};
This is the one I called ListList above
class LinkListList: public LinkList
{
public:
LinkListList(); //modified contructor initiates the pointers start and ptrNode
~LinkListList(); //modified destructor deletes all nodes and secondaryList nodes
LinkListList(const LinkListList &original); //copy constructor
bool addSubList(LinkList subList, string commandWord); //calls setPtrNode, then adds the given subList to that node
bool findSubToken(string commandWord, string token); //calls setPtrNode, then calls on that node's secondaryList's findToken function
//returns true if the findToken function returns true, else returns false
string showSubList(string commandWord); //returns a string of tokens, separated by commas and spaces, representing the subList of the given token
string getSubToken(string word, string commandWord); //searches commandWord's subList for a token that begins with the given word.
//Returns the full token if there's a token that begins with the given word, else returns an empty string
private:
struct Node //each node of the linked list, held together by the next pointer
{
string token;
bool second_word; //tells whether or not there is a space within the token (a two-word keyword)
LinkList secondaryList; //keeps a list of all related words
Node *next;
};
Node *start; //pointer to the beginning of the linked list
Node *ptrNode; //this pointer is used for the functions
void setPtrNode(string token); //sets ptrNode to point to the node containing the specified token. ptrNode is NULL if the token could not be found
};
Edit: I see.
Ideally, you'd have just one linked list implementation that can hold any kind of value, including — and here's the kicker — a compound data structure that has a linked list as one of its fields. In the code you have right now, the inheritance is actually unnecessary as far as I can tell, you're generally duplicating all the hard work of creating a linked list, and you're mixing the linked list data structure with your higher-level object representing the various lists of words.
Here is one possible way I might structure the data structures here:
The generic linked list:
template <typename T>
class LinkedList { ... };
A class that uses linked lists to represent whatever list of words you're making:
class TokenList {
struct Token {
string word;
LinkedList<string> related;
};
LinkedList<Token> list;
// Methods to add/search/remove tokens from the lists and sublists
};
(Also, I suspect the data structure you're actually seeking is a map, but that's another discussion.)
Looks like you're looking for a Has-A relationship and not an Is-A relationship.
I would suggest for your LinkListList to have a List of lists of the first type, instead of using inheritance.
I think your List class needs some virtual functions. It doesn't know anything about ListList, so it can hardly be expected to use the derived class's members.
A virtual function in a base class allows inheritors to provide an override of it. When the base class (or external callers seeing it as the base class) calls the function in a derived instance, it knows to look for that override in the derived class instead of using the one in the base class.
If you control the base List class (as opposed to a supplied framework class) you could restructure it to use virtual functions in key places so that the derived ListList class could redirect them to its own logic while still being accessible to code accessing it as a List--for example, so you could create a ListList and pass it to something expecting a List.
But if you can't change List and it doesn't already have virtual functions you can override, you may not be able to do it. You might have to look for a different (lower) base class, or create ListList (or LinkedList?) as a separate class rather than derived. It could provide a ToList() function to export its contents as a standard List (and a constructor taking a List and/or a From(List) function to import from a List back into a ListList). But it's probably more work to use it that way, depending on what you actually need to do with it that had you looking to derived from List in the first place.
Edited: With the code you've now posted, it looks like inheritance may not be what you actually need, after all, as #rmn points out. So while this answer hopefully explains a little about how virtual functions work (as applicable to question originally posed), it may not apply to what you're really trying to do with the two classes.