C++ out-of-line definition - c++

I'm making a hash table and my class HashTable consists of the following struct and the following function in my header file:
class HashT
{
public:
struct Node
{
std::string key;
std::string value;
Node* next;
};
Node** HashTArray;
void HashTCopy(struct Node** h1, struct Node** h2, unsigned int sz);
HashT(const HashT& hm); (copy constructor that calls HashTCopy)
unsigned int initialBucketCount = 10;
};
In my source file, I define the function as such and used it in my copy constructor:
void HashT::HashTCopy(struct Node** h1, Node** h2, unsigned int sz)
{
...
}
HashT::HashT(const HashT& hm)
{
new_HashT = new Node* [hm.initialBucketCount];
HashTCopy(new_HashT, hm.HashTArray, hm.initialBucketCount)
}
When I try to compile this I get an error saying out-of-line definition HashT::HashTCopy..." and.... note: type of 1st parameter of member declaration does not match definition. 'struct Node**' aka 'HashMap::Node** vs 'struct Node** aka HashMap::Node**'. The compiler points to struct... 'void HashTCopy(struct Node** h1,....)`. I can't seem to figure out the problem. My declaration and definition match up so what is the issue here? Thanks

In the implementation, remove the struct before Node, i.e. change:
void HashT::HashTCopy(struct Node** h1, Node** h2, unsigned int sz)
to
void HashT::HashTCopy(Node** h1, Node** h2, unsigned int sz)
You don't need to write struct before variables of struct type in C++ (that's a C thing, and an outdated C thing at that). Your doing so here is confusing the compiler about what scope the name Node should appear in.
The Node struct is defined within the HashT class's namespace, so its full name is HashT::Node. Normally, types in a member function's argument list can be implicitly resolved within the class' namespace, without having to write HashT:: in front of them. But the redundant struct here seems to be throwing it off, and making it think that you're talking about some other Node struct outside of the HashT class, which it can't find a definition for, and which doesn't match the class declaration.
I'm not sure what the standard says about this, so the compiler may actually be in error here, but I'd bet that removing the struct will fix it.

Make the following changes:
class HashT
{
public:
struct Node
{
std::string key;
std::string value;
Node* next;
};
Node** HashTArray;
static void HashTCopy(Node** h1, Node** h2, unsigned int sz);
HashT(const HashT& hm); (copy constructor that calls HashTCopy)
unsigned int initialBucketCount = 10;
};
void HashT::HashTCopy(HashT::Node** h1, HashT::Node** h2, unsigned int sz)
{
...
}
HashT::HashT(const HashT& hm)
{
new_HashT = new HashT::Node* [hm.initialBucketCount];
HashT::HashTCopy(new_HashT, hm.HashTArray, hm.initialBucketCount)
}
I think that the error is from the compiler not knowing exactly from where to get the Node structure, which is in the class HashT, so that by specifying the namespace (the class) in which the struct resides, will solve the provlem,

HashT.h:
#ifndef HASHT_H
#define HASHT_H
#include <iostream>
class HashT
{
public:
struct Node
{
std::string key;
std::string value;
Node* next;
};
Node** HashTArray;
void HashTCopy(struct Node** h1, struct Node** h2, unsigned int sz);
HashT(const HashT& hm);
unsigned int initialBucketCount = 10;
};
#endif
HashT.cpp:
#include "HashT.h"
void HashT::HashTCopy(struct Node** h1, Node** h2, unsigned int sz)
{
//...
}
HashT::HashT(const HashT& hm)
{
Node** new_HashT = new Node* [hm.initialBucketCount];
HashTCopy(new_HashT, hm.HashTArray, hm.initialBucketCount);
}

i had such problem in one of my QT project i resolved it by moving strut definition to top in header file
so try something like this by updating header filer to.
struct Node
{
std::string key;
std::string value;
Node* next;
};
class HashT
{
public:
Node** HashTArray;
void HashTCopy(struct Node** h1, struct Node** h2, unsigned int sz);
HashT(const HashT& hm); (copy constructor that calls HashTCopy)
unsigned int initialBucketCount = 10;
};

Related

Difference Between "struct Obj* obj" and "Obj* obj"

struct Element{
Element() {}
int data = NULL;
struct Element* right, *left;
};
or
struct Element{
Element() {}
int data = NULL;
Element* right, *left;
};
I was working with binary trees and I was looking up on an example. In the example, Element* right was struct Element* right. What are the differences between these and which one would be better for writing data structures?
I was looking up from this website:
https://www.geeksforgeeks.org/binary-tree-set-1-introduction/
In C, struct keyword must be used for declaring structure variables, but it is optional(in most cases) in C++.
Consider the following examples:
struct Foo
{
int data;
Foo* temp; // Error in C, struct must be there. Works in C++
};
int main()
{
Foo a; // Error in C, struct must be there. Works in C++
return 0;
}
Example 2
struct Foo
{
int data;
struct Foo* temp; // Works in both C and C++
};
int main()
{
struct Foo a; // Works in both C and C++
return 0;
}
In the above examples, temp is a data member that is a pointer to non-const Foo.
Additionally, i would recommend using some good C++ book to learn C++.
In C++, defining a class also defines a type with the same name so using struct Element or just Element means the same thing.
// The typedef below is not needed in C++ but in C to not have to use "struct Element":
typedef struct Element Element;
struct Element {
Element* prev;
Element* next;
};
You rarely have to use struct Element (other than in the definition) in C++.
There is however one situation where you do need it and that is when you need to disambiguate between a type and a function with the same name:
struct Element {};
void Element() {}
int main() {
Element x; // error, "struct Element" needed
}

How to Access Members in a Linked List Inside a Linked List

I need to access members of a linked list class inside of a linked list. I can manage my Artist list okay, but cannot set int x in my SongList class. I've tried setting it with *(temp->songHead).x = 5;, *temp->songHead.x = 5;, *(temp->songHead)->x = 5;, and *temp->songHead->x = 5;.
When I compile it, I get the error:
invalid use of incomplete type 'struct songList'
How can I set int x?
#ifndef LINKED_LIST
#define LINKED_LIST
class SongList{
public:
SongList();
int x;
void add(int x);
private:
struct Song{
char *name;
int minutes;
int seconds;
int views;
int likes;
Song *next;
};
Song *head;
};
class LinkedList{
public:
LinkedList();
~LinkedList();
void test(int x);
void add(char ch);
bool find(char ch);
bool del(char ch);
void list();
private:
struct Artist{
char character;
Artist *next;
struct songList *songHead;
SongList ptr;
};
Artist *head;
};
#endif
// Code to set int x
void LinkedList::test(int x){
struct Artist *temp;
temp = head;
*(temp->songHead).x = 5;
}
C++ doesn't require you to add struct in front of declarations of variables containing structs. Adding it allows you to use undefined types in your variable declarations.
If you remove struct you'll quickly see the true cause of your error:
songList *songHead;
Will give an error something like this (this is from clang, other compilers may not be as helpful):
error: unknown type name 'songList'; did you mean 'SongList'?
Your access to songHead is also incorrect:
*(temp->songHead).x = 5;
This is equivalent to:
*(temp->songHead.x) = 5;
What you actually want is:
(*temp->songHead).x = 5;
Or more simply:
temp->songHead->x = 5;

Is this a correct destructor for my Node struct?

I have this C++ struct:
struct Node {
char symbol;
unsigned int index;
vector<Node*> next;
// Constructors
Node():symbol('$'), index(0), next(0) {}
Node(char &c, const unsigned int &ind):symbol(c), index(ind), next(0) {}
// Add a new character
Node* add(char &c, const unsigned int &num) {
Node *newChar = new Node(c, num);
next.push_back(newChar);
return newChar;
}
// Destructor
~Node() {
for (int i = 0; i < next.size(); i++)
delete next[i];
}
};
(I know it might be better to make it a class but let's consider it as it is).
I'm not quite sure if I wrote the correct destructor for this. In the main function I'm using a root node:
Node *root = new Node();
Although the code won't leak memory (as long as you delete the root node in main), it isn't really optimal.
You should avoid new and delete and instead prefer smart pointers. In this case, use unique_ptr.
Also, don't create the root node on the heap, just create it normally like so:
Node root;
// use root normally
You also don't follow the rule of five properly, and you won't even need to worry about it if you used unique_ptr since you wouldn't have a custom dtor. There's also no reason to take the c and ind by ref and const ref, just pass them by value (because you don't even change them, and its as cheap passing by value as by ref for primitives).
With these changes, the code looks like this
struct Node {
char symbol;
unsigned int index;
vector<std::unique_ptr<Node>> next;
// Constructors
Node():symbol('$'), index(0){}
Node(char c, unsigned int ind):symbol(c), index(ind) {}
// Add a new character
Node* add(char c, unsigned int num) {
next.push_back(std::make_unique<Node>(c, num));
return next.back().get();
}
};

char array interpreted as a char pointer in a constructor help please

#ifndef ASSETS_H_INCLUDED
#define ASSETS_H_INCLUDED
#include <vector>
#include string.h>
const int ID_Max = 100;
typedef char ID[ID_Max];
struct node;
struct people{
std::vector<ID> T_ID;
std::vector<node*> Nodes;
people(ID t, node* person){
T_ID.push_back(t);
Nodes.push_back(person);
}
people(){}
};
struct node {
ID T_ID;
node* Parent;
people* leftChildren;
node* rightChild;
node(ID t, node* p, node* l, node* r) :I_ID(t), Parent(p), rightChild(r)
{leftChildren = new people(); }
};
#endif // ASSETS_H_INCLUDED
My problem is this it is interpreting ID as a char pointer when in the constructor so this is the constructor people::people(char*, node*) when I want people::people(char[ID_Max], node*) same for node. If you have advise it would be very appreciated.
If you write a function signature with an array type in it, it's the same as using a pointer, e.g. this:
void f(char p[]);
is the same as this:
void f(char *p);
That looks like it's the root of your problem here. You might be better off with e.g. a std::array<char,ID_Max> (in C++11), or a std::vector<char> (in C++98). You can then get a pointer to the start of the contiguous memory it contains using &cont[0]. As a minor nit, I seem to recall that the memory for vector wasn't strictly guaranteed to be contiguous in C++98, but it always was contiguous in practice (you could rely on it). The wording was fixed in C++03.

I cannot compile using template in C++

I compiled the following cords with g++
#include <iostream>
#include <string>
using namespace std;
template<class T>
class Node<const char*>{
private:
string x_;
Node* next_;
public:
Node (const char* k, Node* next):next_(next),x_(k){}
string data(){return x_;}
Node *get_next(){return next_;}
};
$ g++ -c node01.cc
node01.cc:5: error: ‘Node’ is not a template
What's wrong?
I'm begginer for c++
You're mixing up declarations and instantiations. When you declare a template, you don't specify a type immediately after its name. Instead, declare it like this:
template<class T>
class Node {
private:
const T x_;
Node *next_;
public:
Node (const T& k, Node *next) : x_(k), next_(next) { }
const T& data(){return x_;}
Node *get_next(){return next_;}
};
Your original declaration also confuses string, const char *, and generic types that should be in terms of T. For a template like this, you probably want to let the user define the type of the member (x_). If you explicitly declare it as const char * or string, you're losing genericity by limiting what the user can use for T.
Notice that I changed the types of the instance variables, the parameters of the constructor and the return type of data() to be in terms of T, too.
When you actually instantiate a variable of the template type, you can provide a concrete type parameter, e.g.:
int main(int argc, const char **argv) {
Node<char*> *tail = new Node<char*>("tail", NULL);
Node<char*> *node = new Node<char*>("node", tail);
// do stuff to mynode and mytail
}
Whenever you write the template name Node outside the template declaration, it's not complete until you provide a value for the parameter T. If you just say Node, the compiler won't know what kind of node you wanted.
The above is a little verbose, so you might also simplify it with a typedef when you actually use it:
typedef Node<char*> StringNode;
int main(int argc, const char **argv) {
StringNode *tail = new StringNode("tail", NULL);
StringNode *node = new StringNode("node", tail);
// do stuff to mynode and mytail
}
Now you've built a linked list of two nodes. You can print out all the values in the list with something like this:
for (StringNode *n = node; n; n = n->get_next()) {
cout << n->data() << endl;
}
If all goes well, this will print out:
node
tail
Your class declaration should look like this:
template<class T>
class Node{
private:
T x_;
Node* next_;
public:
Node (const T& k, Node* next):next_(next),x_(k){}
T data(){return x_;}
Node *get_next(){return next_;}
};
Notice how I removed all references to string or const char * and replaced them with the generic type T. Your class, since it is templated, should not refer to any specific type but should do everything in terms of the generic T type.
The const char * is specified later when you declare a Node variable. Or it could be any other type, not just const char *. The point is, when you're declaring the Node class you just use the generic type T in the code without reference to any specific type. You specify a specific type only when you actually use a Node.
Node<const char *> stringNode("foo", NULL);
Node<int> intNode(5, NULL);
This has allowed us to have a single definition of the Node class but be able to use it to create both nodes where the data is a string and nodes where the data is an integer. Hooray templating!