0

Let's say I have a main.cpp, class1.cpp, class1.h, as well as other header files that won't be specified:

class1.h

#pragma once

class Class1 {
public:
  Class1(int val);
  void pubFunc();
private:
  int val1;
  void privFunc();
}

class1.cpp

#include "class1.h"

Class1::Class1(int val) {
  val1 = val;
}

void Class1:pubFunc() {
  if (val1 > 0)
    privFunc();
}

main.cpp

#include "class1.h"
#include "anotherclass.h"

AnotherClass ac;

int main() {
  Class1 c1(10);
  c1.pubFunc();
}

Class1::privFunc() {
  ac.doSomething;
}

I want Class1::pubFunc() to essentially trigger another function that can make use of AnotherClass, without including its header inside class1.cpp. This is the method that I thought of, but it feels disorganized, and I'm not too keen on putting the class instances outside of main(). The only other way I can think of doing this making Class1::pubFunc() return a string, which maps to a function, but I don't know if that's any better.

Mohit
  • 1,225
  • 11
  • 28
LaPXL8R
  • 39
  • 2
  • 11
  • 5
    Possible duplicate of [Why have header files and .cpp files?](https://stackoverflow.com/questions/333889/why-have-header-files-and-cpp-files) – eyllanesc Apr 20 '18 at 04:02
  • Hey, if it works, it's ok, right? That used to be my professor's mentality. He couldn't be more wrong. – DeiDei Apr 20 '18 at 04:09
  • it is clearer to include the headers of the classes you use, where they actually are used. Otherwise when somebody else than you include "class1.h" in their program they will directly get an error about anotherclass. IOW if class1.cpp needs anotherclass then include anotherclass there. – AndersK Apr 20 '18 at 04:27
  • Can you forward declare the other class? – Matt Apr 20 '18 at 04:34
  • any reason you want to avoid include another_class.h? – Bryan Chen Apr 20 '18 at 05:04
  • 1
    This sounds really unusual and as you or your teacher has a java background. There is no reason for having just one class defined in a h or cc file. Why don't you just put both together in a single file if they are related? Even if they are not strongly related it is not unusual to include other classes' header files. Note: You will do it most of the time in the cc (implementation) file and forward declare other classes in the header. Please make sure you understand when a complete type is required (google: incomplete types c++) – Jan Christoph Uhde Apr 20 '18 at 05:21

2 Answers2

2

Misconception. A class in C++ does not need to have its own *.cpp file and there are pragmatical reasons to avoid having lots of tiny *.cpp files (and prefer instead having less *.cpp files, each defining several related classes and functions, so being slightly bigger).

A given translation unit (e.g. the *.cpp files and all the header files it is #include-ing) can (and usually does) define and declare several class-es and functions.

In practice, you code in C++ by using several standard containers or other standard C++ facilities provided by standard C++ headers, such as smart pointers from <memory>, strings from <string>, vectors from <vector>, sorting functions from <algorithm> and so on. The powerful C++ standard library is one of the reasons to code in C++ (instead of C, for instance). So you would #include perhaps several standard headers like <vector> or <map>. Standard headers are quite complex: on my Linux machine, #include <vector> generally expands to more than ten thousand of included lines (and that is one of the reasons why C++ code compiles slowly). So it is unwise (but possible) to have many small C++ files of a hundred lines each which are including some standard header, because a small yourcode.cpp file containing #include <vector> and two hundreds lines of your C++ code is expanded to much more: the compiler parses about 10000 lines of code (LOC) from <vector> and 200LOC of your code, so 10200 LOC in total.

BTW, you can ask your compiler to give the preprocessed form of your translation unit (with GCC, using g++ -C -E yourcode.cpp > yourcode.ii) and look (with an editor or a pager) inside that yourcode.ii.

(your example is not genuine C++11 code; in practice, it should often use standard containers and some other features -smart pointers, threads, standard algorithms...- of the rich C++ standard library, but it does not)

So I recommend to have your *.cpp containing at least a thousand or two of your C++ source code lines, and of course they could define several of your related classes (and functions). In some cases, a single C++ class might be implemented in several C++ files (because that class has a lot of methods).

BTW, in your C++ classes, a lot of small functions (including member functions) are inlined and you'll define them in some of your header file.

I recommend studying the source code of several C++ free software projects for inspiration. You'll find many of them on github or elsewhere.

Basile Starynkevitch
  • 223,805
  • 18
  • 296
  • 547
2

Your question is a consequence of an earlier questionable decision -- to use a global variable to share an instance of AnotherClass between main() and Class1.

If you break that dependency, perhaps by using a callback, or an interface, then your need to scatter Class1 member function definitions across multiple compilation units will disappear as well.

Here's one way you might cure the dependency:

class1.h

#include <functional>

class Class1
{
public:
  Class1(int val, std::function<void(void)> callback);
  void pubFunc(void);
private:
  std::function<void(void)> do_the_thing;
  int val1;
};

class1.cpp

#include "class1.h"

Class1::Class1(int val, std::function<void(void)> callback)
   : val1(val), do_the_thing(std::move(callback))
{
}

void Class1:pubFunc(void)
{
  if (val1 > 0)
    do_the_thing();
}

main.cpp

#include "class1.h"
#include "anotherclass.h"

int main(void)
{
  AnotherClass ac;

  Class1 c1(10, std::bind(&AnotherClass::doSomething, ac));
  // can also write as     [](){ ac.doSomething(); }
  c1.pubFunc();
}
Ben Voigt
  • 277,958
  • 43
  • 419
  • 720
  • This answer is correct - but misleading for a beginner. Why do you use std::function? (I can already see the lambda:) – Jan Christoph Uhde Apr 20 '18 at 05:29
  • 1
    @JanChristophUhde: The lambda is capturing, so it isn't compatible with an ordinary pointer. And introducing a template to handle the lambda's exact type seems much more advanced than dropping in `std::function`. – Ben Voigt Apr 20 '18 at 06:01
  • I think a template is more flexible and allows for less overhead. Additionally with C++20 you can even ensure some properties with easy syntax e.g. `template requires std::invocable` – Jan Christoph Uhde Jul 06 '22 at 19:24
  • @JanChristophUhde: And completely incomprehensible to the user asking the question. The purpose of the answer is to explain, not to provide copy+paste-ready code. – Ben Voigt Jul 06 '22 at 19:45