Search code examples
c++headerinclude

A header file included in another header file. while including one of the files in main.cpp, both get included. how to prevent this?


For example, Let's suppose there are "a.h", "b.h" and "source.cpp"

// file: a.h
int functionA(int value) {
    ...
    return something
}

a.h is the header file. b.h uses functionA from a.h

// file: b.h
#include "a.h"

class className {
public:
    int functionB(const int & val) {        // functionB uses functionA
        return functionA(val);
    }
};
// file: Source.cpp
#include "b.h"

int main() {
    className obj;
    obj.functionB();        // All good But,
    functionA();         // I don't want main to access a.h's function
    return 0;
}

I don't want the Source file to access a.h's functions. Is there any way to restrict source.cpp from accessing functions from a.h

Here's what I've been trying to do. Consider ComplexNumbers.h and main.cpp

// ComplexNumbers.h uses <cmath> header's function
#include <cmath>

namespace math {
class ComplexNumber {
private:
    double real, imag;
public:
    ComplexNumber(double r, double i) {
        real = r;
        imag = i;
    }
    double getArgument() {        // returns the angle made by the complex number with x-axis
        return atan(imag/real);    // Uses function from <cmath>
    }
};  // class ComplexNumber
}   // namespace math
// Main.cpp
#include "ComplexNumbers.h"
#include <iostream>
using namespace std;

int main() {
    math::ComplexNumber z(1,2);    // Obj, All good But,
    cout << atan(1) <<'\n';  // atan() function also works in main.cpp
    return 0;
}

I don't want main.cpp to access <cmath> function via ComplexNumbers.h. Is there any way that the <cmath>'s function only gets used in ComplexNumbers.cpp rather than main.cpp


Solution

  • Is there any way to restrict source.cpp from accessing functions from a.h

    Not without some significant changes to your code. Headers are "copied and pasted" into the file that #includes them, and there is no way to make portions of them inaccessible.

    Consider using C++20 modules

    To solve this, you could be using C++20 modules, which only make exports visible, and allow you to import other modules without making the imported contents visible to other modules. However, C++20 modules are still somewhat unstable, and they're not supported by clang, so you might not want to use them.

    In your case, this would require import <cmath> instead of #include <cmath>, and would have the desired effect.

    Solution using detail namespaces

    A "bandaid" solution that people typically use is a "detail namespace":

    // file: a.h
    namespace detail {
    
    int functionA(int value) {
        ...
        return something
    }
    
    } // namespace detail
    
    // file: b.h
    #include "a.h"
    
    class className {
    public:
        int functionB(const int & val) {
            return detail::functionA(val);
        }
    };
    

    However, this doesn't prevent someone from using detail::functionA when they include b.h, it just makes it so they don't accidentally use it, and the function won't show up for auto-completion.

    In the context of <cmath>, you cannot do this, because you don't control what namespace the functions in <cmath> are in.

    Solution using definitions in source files

    You might also be able to solve this by implementing functionB in a source file. If you did that, then #include "a.h" would no longer need to appear in b.h:

    // b.h
    class className {
    public:
        int functionB(const int & val);
    };
    
    
    // b.cpp
    #include "b.h"
    #include "a.h"
    
    int className::functionB(const int & val) {
        return functionA(val);
    }
    

    In the context of <cmath>, this would require implementing member functions of ComplexNumber in a source file, which is extremely undesirable because it prevents inlining and constexpr.

    Conclusion

    In conclusion, there are some solutions, but all of them have major downsides. However, it's not that bad to "leak" the #include <cmath> into headers which use complex numbers. It's likely that users would have included the math library themselves.