I am implementing a simple Stack class and when I include the header file into my main.cpp file there are undefined reference
error for every function that I used in main
function. But move the implementations from "stack.cpp" to the end of "stack.h", and it works.
These are the files from the project:
stack.h
#ifndef STACK_H
#define STACK_H
#include <exception>
#include <string>
#include <initializer_list>
class StackException : public std::exception {
public:
StackException() = default;
explicit StackException(const std::string& msg) : message{msg} {}
explicit StackException(const char* msg) : message{msg} {}
virtual ~StackException() = default;
virtual const char* what(void) const noexcept { return message.c_str(); }
private:
std::string message;
};
template<typename T>
class Stack {
public:
Stack(const uint64_t& = 8);
Stack(const std::initializer_list<T>&);
Stack(const Stack<T>&);
Stack(const Stack<T>&&) noexcept;
~Stack();
T& top(void) const;
void push(const T&);
const T& pop(void);
bool isEmpty(void) const;
bool isFull(void) const;
const uint64_t& size(void) const;
Stack& operator=(const Stack&);
bool operator==(const Stack&) const;
private:
T* _arr;
uint64_t _size;
uint64_t _allocated;
void reset(void);
void extend(void);
void shrink(void);
};
#endif // STACK_H
stack.cpp
#include "stack.h"
template<typename T>
Stack<T>::Stack(const uint64_t& capacity)
{
_size = 0;
_allocated = capacity;
_arr = new T[_allocated];
}
template<typename T>
Stack<T>::Stack(const std::initializer_list<T>& il) : Stack() {
for(T item : il) insert(item);
}
template<typename T>
Stack<T>::Stack(const Stack<T>& other) : Stack{other._allocated} {
_size = other._size;
for(int i = 0; i < _allocated; i++) _arr[i] = other._arr[i];
}
template<typename T>
Stack<T>::Stack(const Stack<T>&& other) noexcept {
_size = other.size;
_allocated = other._allocated;
_arr = other._arr;
other._arr = nullptr;
other.reset();
}
template<typename T>
Stack<T>::~Stack(void) {
reset();
}
template<typename T>
void Stack<T>::reset(void) {
if(_arr != nullptr) {
delete[] _arr;
_arr = nullptr;
}
_size = 0;
_allocated = 0;
}
template<typename T>
void Stack<T>::extend(void) {
Stack<T> temp{std::move(*this)};
_arr = new T[temp._allocated * 2];
_allocated = temp._allocated * 2;
_size = temp._size;
for(int i = 0; i < temp._allocated; i++) _arr[i] = temp._arr[i];
}
template<typename T>
void Stack<T>::shrink(void) {
Stack<T> temp{std::move(*this)};
_arr = new T[temp._allocated / 2];
_allocated = temp._allocated / 2;
_size = temp._size;
for(int i = 0; i < _allocated; i++) _arr[i] = temp._arr[i];
}
template<typename T>
T& Stack<T>::top() const {
if(isEmpty()) throw StackException("Stack is empty!");
return _arr[_size - 1];
}
template<typename T>
void Stack<T>::push(const T& item) {
if(isFull()) extend();
_arr[_size++] = item;
}
template<typename T>
const T& Stack<T>::pop(void) {
if(isEmpty()) throw StackException("Stack is empty!");
if(_size <= _allocated / 4) shrink();
T& temp = _arr[--_size];
return temp;
}
template<typename T>
bool Stack<T>::isEmpty(void) const {
return _size == 0;
}
template<typename T>
bool Stack<T>::isFull(void) const {
return _size >= _allocated;
}
template<typename T>
const uint64_t& Stack<T>::size(void) const {
return _size;
}
template<typename T>
Stack<T>& Stack<T>::operator=(const Stack<T>& other) {
if(&other == this) return *this;
if(other._allocated != _allocated) {
delete[] _arr;
_arr = new T[other._allocated];
_allocated = other._allocated;
}
_size = other.size;
for(int i = 0; i < _allocated; i++) _arr[i] = other._arr[i];
return *this;
}
template<typename T>
bool Stack<T>::operator==(const Stack<T>& other) const {
if(_size != other._size) return false;
for(int i = 0; i < _size; i++) {
if(_arr[i] != other._arr[i]) return false;
}
return true;
}
main.cpp
#include <iostream>
#include "stack.h"
using namespace std;
int main() {
Stack<int> test(8);
test.push(3);
cout << test.size() << endl;
return 0;
}
In "main.cpp" I replaced #include "stack.h"
with #include "stack.cpp
and it worked without error. Using g++ stack.cpp main.cpp -o a
outputs the same errors when I use #include "stack.h"
.
This is certainly not my first time separating headers and implementations in multiple files but this is quite new to me. So shall I go on and use #include "stack.cpp"
(which I don't suppose is a good idea)? Is there any reason to this?
Aucun commentaire:
Enregistrer un commentaire