开发者

What kind of bad things would happen if you write the whole class in a single file in C++?

开发者 https://www.devze.com 2022-12-23 06:22 出处:网络
In C# or Java, classes are declared and defined at the same time. In C++, the norm is to do that separately. What if we write the whole clas开发者_如何学Gos in one , say .cpp, file and include that in

In C# or Java, classes are declared and defined at the same time. In C++, the norm is to do that separately. What if we write the whole clas开发者_如何学Gos in one , say .cpp, file and include that in files that references to it, what kinds of bad thing technically would happen besides a lengthened compilation process?


If your implementation of MyClass is all in the header file MyClass.h then any file you needed to implement MyClass will be included whenever someone includes MyClass.h.

If you change any part of MyClass.h, even if it's trivial (such as adding a comment or even a space) then all files that include it will have to recompile, even if the interface hasn't changed.

Neither of these matters for toy projects, but as you noted, when you have a program that consists of hundreds (or thousands, etc.) of class files, the added compilation time alone makes it worthwhile to separate out implementation from interface.

For instance, if I have the following:

// MyClass.h
#include <iostream>
#include <iomanip>
#include <sstream>
#include <string>

#include "Inventory.h"

class MyClass
{
public:
  MyClass();

  void processInventory(Inventory& inventory)
  {
    // Do something with each item in the inventory here
    // that uses iostream, iomanip, sstream, and string
  }
private:
  // ...
};

It would more ideomatically be written as:

// MyClass.h
class Inventory;

class MyClass
{
public:
  MyClass();

  void processInventory(Inventory& inventory);
private:
  // ...
};

// MyClass.cc
#include "MyClass.h"

#include <iostream>
#include <iomanip>
#include <sstream>
#include <string>

#include "Inventory.h"

MyClass()::MyClass()
{
}

void MyClass()::processInventory(Inventory& inventory)
{
  // Do something with each item in the inventory here
  // that uses iostream, iomanip, sstream, and string
}

Notice: Including MyClass.h doesn't mean iostream, iomanip, sstream, string, or Inventory.h have to be parsed. Changing how processInventory works doesn't mean all files using MyClass.h have to be recompiled.

Notice how much easier it can be to figure out how to use MyClass now. Header files serve an important purpose: they show people how to use your class. With the modified MyClass.h it's easy to see the list of functions. If each function is defined in the header, then you can't look at just the list of functions. That makes it harder to figure out how to use the class.


You may break the one definition rule.

If you write this:

class foo
{
public:
    void doit();
};

foo::doit() {}

and include that in multiple classes, you will have multiple definitions of foo::doit and your link will fail.

But if you make all your classes inline, either by defining them within the class declaration:

class foo
{
public:
    void doit() {
    }
};

or by explicitly making them inline:

class foo
{
public:
    void doit();
};

inline void foo::doit() {}

then you can include that file as many times as you like.


The linker will see multiple definitions of the class's members when you try to combine multiple such objects. Thus, you won't be able to produce a binary from source files that include anything in more than one place.


Typically you separate the declaration and definition of a class. This allows you to use your class in different source files by simply including the declaration.

If you include a .cpp which has both declaration and definition into 2 different source files then that class will be doubly defined.

Each .cpp that the class is included into will compile fine into object files. However each class must have only 1 definition total or else you will not be able to link your object files together.


The most important thing to understand about #include contrasted with other languages importing methods, is that #include COPIES the contents of that file where the #include directive is placed. So declaring and defining a class in the same file will create three things:

  • Significantly increase your compile
    times.

  • If your definitions are not inline you will get linker errors, since the compiler finds multiple
    definitions to the same functions

  • That would expose the implementation to the user, instead of only the interface.

That is why it is common practice to define large classes in separate files, and on some ocassions, really small classes with small implementations (like smart pointers) in one file(To also implicitly inline methods).


@Bill

I think it is important to underscore Bill's point:

Notice how much easier it can be to figure out how to use MyClass now. Header files serve an important purpose: they show people how to use your class.

the .h file being more or less the "public" doc to allow the understanding of how your class works in some ways conceptually--an Interface. Remember the source file should be thought of as proprietary. I remember learning a lot about how Unix worked in my early C/C++ days by reading header files. Also remember that inline function complexities should be no more than accessor's


A big reason for a class to be defined in a cpp-file is that it isn't needed publically, it is just a helper function (like e.g. a functor). Some people seem to be afraid to put the complete class in the cpp-file, while that just shows your intent of only using the class there.


Files are usually the atoms of your version control system - if you partition things sensibly into different files, then it becomes possible for a team of developers to check out only the parts they each need to work on. Put everything in one file and you can't do that.

0

精彩评论

暂无评论...
验证码 换一张
取 消