0

I'm making a heap class to be importable with heap.h and my constructors including bool types do not work, yet every other constructor and function imported works.

Here is what's in heap.h:

#ifndef __HEAP_INCLUDED__
#define __HEAP_INCLUDED__

#include <iostream>
#include <vector>

using namespace std;

class heap{
int capacity;
bool isMinHeap;  //1 is min heap -- ascending order
vector<int> * content;
public:
heap();
heap(bool t);
heap(vector<int> * input);
heap(vector<int> * input, bool t);

void print();
void prettyPrint();
int parent(int i);
int leftChild(int i);
int rightChild(int i);
int size();
int getMax();
void insert(int data);
void heapifyDown(int index);
void heapifyUp(int index);
int invalidChild(int index);
int deleteMax();
int deleteMin();
bool minDir();
int at(int index);
};

vector<int> * heapSort(vector<int> * input);

void swap(vector<int> * vec, int a, int b);

#endif

Here are the defined constructors in heap.cpp. Note, all constructors work fine when I add a main to this file to test stuff:

class heap{
    vector<int> * content;
    int capacity = 256;
    bool isMinHeap;  //1 is min heap -- ascending order
        
    public:
    heap(){
        content = new vector<int>;
        isMinHeap = 0;
    }
    heap(bool t){
        content = new vector<int>;
        isMinHeap = t;
    }
    heap(vector<int> * input){
        content = input;
        isMinHeap = true;
        for(int i = content->size()/2; i >= 0; i--){
            heapifyDown(i);
        }
    }
    heap(vector<int> * input, bool t){
        content = input;
        isMinHeap = t;
        for(int i = content->size()/2; i >= 0; i--){
            heapifyDown(i);
        }
    }
//other functions below
}

The constructors with bool do not work in main.cpp, which has #include "heap.h" at the top. The files are all in the same directory and I am compiling with this command: g++ heap.cpp main.cpp -o main. Why do two of my constructors not work?

The error I see is

/usr/bin/ld: /tmp/ccwomODk.o: in function `main':
main.cpp:(.text+0x4e2): undefined reference to `heap::heap(bool)'
collect2: error: ld returned 1 exit status

-Wall does not elaborate on the issue. I'm pretty sure the issue is with my linking somewhere because the constructors work inside of heap.cpp when I use them in there.

Harris B
  • 71
  • 6
  • 1
    Unrelated (probably): [Phear the double underscore](https://stackoverflow.com/questions/228783/what-are-the-rules-about-using-an-underscore-in-a-c-identifier)!!!!!! – user4581301 Feb 11 '22 at 01:07
  • Your `heap.h` declares a class heap, and your `heap.cpp` declares another one (this one with more definitions). Put declarations in the header, and only definiitions in the implementation file. (e.g. in `heap.cpp` have `#include "heap.h" heap::heap(bool t) { ... }`. – Adriaan de Groot Feb 11 '22 at 01:09
  • Your cpp file looks wierd... – Vlad Feinstein Feb 11 '22 at 01:09
  • 2
    This is not how you define members of a class out-of-line. You are giving two different definitions of the class `heap` resulting in an ODR violation and undefined behavior. – user17732522 Feb 11 '22 at 01:09
  • Unrelated (probably): [Why is "using namespace std;" considered bad practice?](https://stackoverflow.com/questions/1452721/why-is-using-namespace-std-considered-bad-practice) – SuperStormer Feb 11 '22 at 01:10
  • Did you first try to write a simple class declaration, and simple class definition? If you did that, you should have never wound up with an entire block of code (the heap.cpp) looking like that. `class foo { public: void someFunction(); };` would be in a header, and in the cpp file: `#include #include void foo::someFunction() { std::cout << "stuff"; }`. The mistake you made is a tell-tale sign you either did not follow the C++ book you're using, or you guessed what a class implementation looked like, and wrote all of this, with the final results ending up all wrong. – PaulMcKenzie Feb 11 '22 at 01:19
  • This doesn’t address the question, but names that contain two consecutive underscores (`__HEAP_INCLUDED__`) are reserved for use by the implementation. Don’t use them in your code. – Pete Becker Feb 11 '22 at 01:31

2 Answers2

3

What you are doing with the class in the .cpp file is wrong. You are not allowed to define the class twice. There must only be one class heap { /*...*/ }; in the program (but it may be included in multiple .cpp files). Otherwise the one-definition-rule (ODR) is violated and the program has undefined behavior.

So remove everything you are showing from heap.cpp.

To define the constructors of heap in the heap.cpp file, you need to use this syntax:

#include "heap.h"

heap::heap() {
    /*...*/
}

heap::heap(bool t) {
    /*...*/
}

//...

and so on. The other member functions must be defined in a similar way, e.g.:

void heap::print() {
    /*...*/
}

Furthermore, if you want to have a default member initializer as in

int capacity = 256;

add it in the declaration in the .h file instead.


I also want to add that having a pointer-to-std::vector as member is almost surely a wrong approach as well, but out-of-scope for the question.

user17732522
  • 53,019
  • 2
  • 56
  • 105
  • What's wrong with using std::vector? I make frequent use of size() and pushback(). Access and modification is a little annoying but it works – Harris B Feb 11 '22 at 07:53
  • 1
    @HarrisB The vector itself is not the problem. That it is `vector * content;` instead of `vector content;` is suspicious. What makes you use a pointer here? – user17732522 Feb 11 '22 at 07:54
0

When you declare a program element such as a class, function, or variable, its name can only be "seen" and used in certain parts of your program. The context in which a name is visible is called its scope. For example, if you declare a variable x within a function, x is only visible within that function body.

It seems you broke ODR rule so bad. Your class members including constructors has no body declared in the source file(heap.cpp). Use '::' to make class members have a body:

//heap.cpp
"heap.h"
heap::heap()
{
}
heap:heap(vector<int> * input, bool t)
{
}
int heap::parent(int i)
{
    return i;
}
// this is how you create a body for function that are class members
// the same should be done for all other functions