简体   繁体   中英

How can I call functions from one .cpp file in another .cpp file?

I tried looking this up and got mixed results using header files and such.

Basically I have multiple .cpp files with all my functions I made for use with binary trees, BST , linked lists, etc.

Instead of having to copy and paste functions as I need them, I want to just be able to do a:

#include <myBSTFunctions.h>

And be able to call and use my own functions.

What are the steps to accomplish this? Make a header file with all the function prototypes I used?

And where should I place the .cpp and header file with all the actually functions?

Is there a way I can call the directory of the functions file directly?

Ie, I'm more thinking of having it in the same folder with the main source .cpp file to share with some of my colleagues.

How can I accomplish this?

On Windows and the MinGW compiler.

Declare functions in a header

//MyFunctions.h
int myFunction1(int,int);
int myFunction2(int,int);

Implement them in MyFunctions.cpp

//MyFunctions.cpp
#include "MyFunctions.h"
int myFunction1(int a, int b){
    //your code
}
int myFunction2(int a, int b){
    //your code
}

Include the header in whatever file you want

//OtherFile.cpp
#include "MyFunctions.h"
//Now you have access to the functions defined in MyFunctions.h in this file

I dont know miniGW but it should look something like g++ otherfile.cpp MyFunctions.cpp ...

You seems to be missing some pretty basic concepts in how to build a program. I'm going to give you a very basic primer, but you will have to go and find more complete answers elsewhere to really understand what's going on and to get the specifics for your setup.

  1. You generally tell the compiler to compile each of your cpp files. When a cpp file has an #include statement, that basically copies and pastes the include d file into your cpp file before compiling (this is done by the preprocessor). Each of these complete units (cpp file, with includes) processed by the compiler is called a translation unit . Each translation unit produces one object file .

  2. Object files contain compiled code, but they are often not complete. That is, they contain references to code that are not contained in them. Basically, they can say "now call this function, I don't know where it is or what it does, but you should call it".

  3. The linker is then used to link object files, perhaps together with libraries, into an executable (or a library). The linker's job is to "resolve" all of the references to external code in each object file by finding the relevant code in other object files and libraries.

  4. Libraries come in two flavours: shared libraries ( .dll s in Windows) and static libraries. A static library is linked into the executable (or other library) by the linker, meaning you can then use the executable without the library (relevant library code becomes part of the executable). You can also link an executable/library against a shared library, in which case you'll need a copy of that shared library every time you run your executable -- the operating system will need to dynamically link your compiled code to the shared library before running it.

So, back to your question.

You have, broadly, three choices: compile then link all of your cpp files directly each time in a single project; compile useful reusable code into a static library, then link your project against it; or compile useful reusable code into a shared library, link your project against it, and make sure to ship the shared library with the result so it can be run.

Most projects of any reasonable size will combine at least two of these. Multiple cpp files will be part of the project code, which will be compiled as separate translation units and given to the linker. Most projects will also use some libraries (either that you write yourself, or that others have written) that are linked statically or dynamically as appropriate.

Unfortunately (imho) C++ as a language doesn't come with a single build system to organise all of this for your (more recent languages often do). There are several different compilers/linkers and many different build systems that can all do all of this. The specific steps you need to take, unfortunately, depend an awful lot on your choice of compiler and build system.

That is quite simple, as JMAA said you should do some research to understand these concepts, but being practical, this is what you would do:

You'll define an functionsExample.cpp where you have to define all your functions and also an functionsExample.h where you'll declare your functions.

You'll have this as the functionsExample.cpp :

#include <iostream>
int example(int x, int y)
{
    return x + y;
}

Ans this as functionsExample.h :

#ifndef FUNCTIONSEXAMPLE_H
#define FUNCTIONSEXAMPLE_H

int example(int x, int y);

#endif 

Then in the cpp you want to run the example function, simply add:

#include "functionsExample.h"

But as I said, you should do some research about header guards, preprocessor directives and files organization to have a deeper knowledge about this. Some links I would recommend:

Header Files

Preprocessor Directives

The easiest way to do this is to use a build tool. My personal preference is meson build, but CMake is more popular. There are others, but you can't go wrong with either of these. Both of these are cross-platform and support different toolchains. This means that as long as your code is standard C++ you can compile it just as easily using MinGW, Visual Studio, G++, or Clang without changing anything. They let you choose from the available toolchains on your platform. Each has a quick start tutorial on its web site.

The configuration file, which you write, specifies what program source files to use and what executables to build. The build chain that you use is selected in the configuration step and after that you can build your executables by running make or ninja (required by meson, recommended for CMake). If you change your source you only need to rerun make or ninja. Of course only the changed parts are rebuilt. Only the executables that are affected by your changes are re-linked as well.

It may be educational to watch a few verbose builds to get familiar with the build process on your system.

ps Traditionally, in #includes you use angle brackets (<>) for system headers and quotes ("") for your own. It has to do with where to look for them first.

Mike

This post is meant to be a complementary answer to existing answers that don't address a very common problem (especially among beginners): including header files with templates implemented in separate source files.


Basically I have multiple .cpp files with all my functions I made for use with binary trees, BST, linked lists, etc.

Since:

  • You have tagged your question with , and
  • C++ has templates, and
  • You have container-like data structures (BST, linked list, etc.) which I assume use templates

I'd like to point out to a common problem not mentionned in the other answers. Consider the following two files:

File class.hpp :

#pragma once // Non-standard but supported by almost (if not) all compilers

// Some class
template<class T> class Class {
    T data;
public:
    Class();
};

// Some function
template<class T> T square(const T& x);

File class.cpp :

#include "class.hpp"
#include <iostream>

template<class T> Class<T>::Class()
{
    std::cout << "Class1()" << '\n';
}

template<class T> T square(const T& x)
{
    return x*x;
}

Try and instanciate a Class object, or call square() :

int main()
{
    Class<int> clss; // should output Class1()
    std::cout << square<int>(3); // should print 9
}

Compile with:

g++ class.cpp main.cpp -o cpptest.exe
./gcc/bin/ld.exe: main.cpp(.text+0x15): undefined reference to 'Class<int>::Class()'
./gcc/bin/ld.exe: main.cpp(.text+0x28): undefined reference to 'int square<int>(int const&)'

The problem

1. Templates

Imagine you have this function:

template<class T> T add(const T& x, const T& y)
{
    return x + y;
}

And you call it like:

int res = add<int>(2, 3);

It's at the moment of the call (ie when the compiler sees the call to add() ) when a copy of the function implementation is created by the compiler:

int add(const int& x, const int& y)
{
    return x + y;
}

And then your call will become:

int res = add(2, 3);

This obviously implies that the template function implementation must be visible to the compiler when the call is found, so the compiler will be able to make a copy of it. And for the compiler to find/see it, it must be in the same translation unit .

That's how templates magic works under the hood. See this answer for more information.

2. The compiler and the linker

Going through the compilation steps:

  1. Replace all the #include directives with the included file contents.
  2. Compile every .cpp file (also called a "translation unit") separately. The result will be an object file for each unit. Note that some code (like in main.cpp ) refers to another code ( class.cpp ). This will be resolved in the next step.
  3. Link the translation units altogether into an executable file. (See JMAA 's answer for more details).

Applying step 1 above, we will have two translation units ( .cpp files):

File class.cpp :

template<class T> class Class {
    T data;
public:
    Class();
};

template<class T> T square(const T& x);

/* <iostream> code ... */

template<class T> Class<T>::Class()
{
    std::cout << "Class1()" << '\n';
}

template<class T> T square(const T& x)
{
    return x*x;
}

File main.cpp :

template<class T> class Class {
    T data;
public:
    Class();
};

template<class T> T square(const T& x);

/* <iostream> code ... */

int main()
{
    Class<int> clss;
    std::cout << square<int>(3);
}

Applying step 2 above, we will have just addresses:

File class.cpp :

/* Nothing to generate for 'Class' definition. Remember, templates are just models (hence the word "template"), not concrete classes/functions. */

/* Nothing to generate for square()'s definition: It's a template, not concrete. */

iostream_object_code

/* Nothing to generate for 'Class' implementation. It's a template, not concrete. */

/* Nothing to generate for square()'s implementation: It's a template, not concrete. */

File main.cpp :

/* Class is not concrete: nothing is generated. */

/* square() is not concrete: nothing is generated. */

iostream_object_code

int main()
{
    class_int_obj_placeholder clss;
    __operator_xx(cout_obj_ref, fn100017(3));
}

Apply step 3 above, and you'll get the undefined reference errors : The linker doesn't know of any fn100017() in any other translation unit. The same is for clss object.

The solution

  1. The obvious fix is to put both the definition and the implementation in the same header file. This way, when included in main.cpp , both will be visible to the compiler.
  2. Or, if you want to keep your definitions and implementations separate, make your implementations in a header file, then include it at the end of the definition header:

File class.hpp :

#pragma once

template<class T> class Class {
    T data;
public:
    Class();
};

template<class T> T square(const T& x);

#include "class_impl.h"

File class_impl.h :

#include <iostream>

template<class T> Class<T>::Class()
{
    std::cout << "Class1()" << '\n';
}

template<class T> T square(const T& x)
{
    return x*x;
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM