-1

I am stuck at how to separate a project into few source files and header files. My current practice seems to be clumsy and mistaken. Any comment is appreciated!

I have four files:

  • main.cpp is the main program. It will create a few tree nodes, and call a function to traverse them.
  • TreeNode.h is the header file where I declare a simple class TreeNode
  • TreeNode.cpp is where I define a constructor of the class TreeNode
  • utils.cpp is where I define a few functions on TreeNode, like printing out the tree.

The question is, where should I include the TreeNode.h file?

  • If I include it both in main.cpp and utils.cpp (since they both use the TreeNode class, my compiler gives me a "duplicate symbol" error. This might be because I included utils.cpp in main.cpp as well.

Like this :

Scanning dependencies of target main
[ 25%] Building CXX object CMakeFiles/main.dir/main.cpp.o
[ 50%] Building CXX object CMakeFiles/main.dir/utils.cpp.o
[ 75%] Linking CXX executable main
duplicate symbol __Z13inorder_printP8TreeNode in:
    CMakeFiles/main.dir/main.cpp.o
    CMakeFiles/main.dir/utils.cpp.o
duplicate symbol __Z16inorderTraversalP8TreeNode in:
    CMakeFiles/main.dir/main.cpp.o
    CMakeFiles/main.dir/utils.cpp.o
ld: 2 duplicate symbols for architecture x86_64
clang: error: linker command failed with exit code 1 (use -v to see invocation)
make[3]: *** [main] Error 1
make[2]: *** [CMakeFiles/main.dir/all] Error 2
make[1]: *** [CMakeFiles/main.dir/rule] Error 2
make: *** [main] Error 2`
  • If I only include TreeNode.h in main.cpp file, the utils.cpp file will not compile. It gives an error error: unknown type name 'TreeNode'

Edit:

Here are the four files:

main.cpp

#include <iostream>
#include <vector>
#include "TreeNode.h"
#include "utils.cpp"

using namespace std;

int main() {
    TreeNode * root = new TreeNode(0);
    root->right = new TreeNode(2);
    root->right->right = new TreeNode(3);

    // inorder_print(root);
    std::vector<int> v = inorderTraversal(root);

    // print out vector
    for (auto i = v.begin(); i != v.end(); ++i){
        std::cout << *i << ' ';
    }
    std::cout << std::endl;
    return 0;
}

TreeNode.h

#ifndef TREE_TREE_H
#define TREE_TREE_H

class TreeNode{
public:
    int val;
    TreeNode * left;
    TreeNode * right;

    TreeNode(int x);
};

#endif //TREE_TREE_H

TreeNode.cpp

#include "TreeNode.h"

TreeNode::TreeNode(int x) {
    val = x;
    left = nullptr;
    right = nullptr;
}

utils.cpp

#include <vector>
#include <iostream>
// #include "TreeNode.h"

// tested correct
void inorder_print(TreeNode * root){
    // print out the tree content in inorder traversal
    while(root != nullptr){
        std::cout << root->val << std::endl;
        inorder_print(root->left);
        inorder_print(root->right);
        break;
    }
}

std::vector<int> inorderTraversal(TreeNode * root){
    std::vector<int> v;
    while(root != NULL){
        v.push_back(root->val);
        if (root->left != NULL){
            v.insert(v.end(), inorderTraversal(root->left).begin(), inorderTraversal(root->left).end());
            break;
        }
        if (root->right != NULL){
            v.insert(v.end(), inorderTraversal(root->right).begin(), inorderTraversal(root->right).end());
            break;
        }
        break;
    }
    return v;
}
8
  • Have you used header guards? You don't include cpp files in another. You create another header file for it. Commented Aug 28, 2018 at 16:12
  • @MichaelSurette No, I've not heard of it before. but thanks for introducing me to it! Commented Aug 28, 2018 at 16:13
  • You should include the TreeNode.h file in any source file that needs it. You should also include it in this question, since it's the core of the problem you're having. Commented Aug 28, 2018 at 16:21
  • Can you provide at least the include section of every file? Commented Aug 28, 2018 at 16:26
  • @PeteBecker Thanks for offering to inspect. Posted now. Commented Aug 28, 2018 at 16:28

2 Answers 2

2

as your compiler output shows, you're compiling both main.cpp and utils.cpp. Your main.cpp includes utils.cpp so functions you defined there are compiled twice hence duplicate symbols.

As the rule of thumb, never include .cpp files. Consider #include as literal inclusion of content of one file into another file. I suppose you tried to resolve the issue that you couldn't use stuff from utils.cpp in mail.cpp. To solve this add function declarations in TreeNode.h (like just a signature of a function, e.g. int foo(double); while keeping their definition in utils.cpp (e.g. int foo(double) { return 0; })

Sign up to request clarification or add additional context in comments.

Comments

0

You can use include guards. For instance:

#ifndef TREENODE_H
#define TREENODE_H

class TreeNode 
{
    // stuff
};

#endif /* TREENODE_H */

Note that the guard name (in this case, TREENODE_H) has to be unique for each header file. And yes, it can be whatever you want.

Edited after question edit:

Don't include utils.cpp. In fact, never include a *.cpp:) change it to #include "utils.h". This is what is causing that linker error.

1 Comment

While that's good advice, it doesn't address the linker error.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.