diff --git a/concepts/headers/about.md b/concepts/headers/about.md index 5be5d6203..51bc6fa82 100644 --- a/concepts/headers/about.md +++ b/concepts/headers/about.md @@ -13,24 +13,28 @@ Some projects use `.hpp` or skip the extension completely. The definitions are located in a separate `.cpp` file. To reunite both parts, this source file starts by including the respective header file. -If you want to write a library called "myLib", that offers a function "my_func" that returns your favorite number, the files would look like this: +If you want to write a library called "quick_math", that offers a function "my_func" that returns your favorite number, the files would look like this: ```cpp -// A file named myLib.h +// A file named quick_math.h #pragma once -namespace magic { - int my_func(int a, int b); +namespace quick_math { + double super_root(double x, int n); } ``` ```cpp -// A file named myLib.cpp -#include "myLib.h" -int magic::my_func(int a, int b) { - return 47 * a + 3 * b; +// A file named quick_math.cpp +#include "quick_math.h" +#include +double quick_math::super_root(double x, int n) { + while(n) { x = sqrt(x), --n;} + return x; } ``` +If you need to include another header, that is only needed by the implementation, the respective `#include` line is only needed in the source file. +Everything that is included in the header, is also available in the `.cpp` file, like the `string` library in the example below. Attention: the `;` is needed after the declaration in the header file, but not after the definition in the source file. ~~~~exercism/note @@ -38,6 +42,47 @@ Many C++ exercises on Exercism start with two almost empty files: header and sou You have to check the `*_test.cpp` file to see the names and namespaces of the expected functions to solve the exercise. ~~~~ +## Classes and Headers + +Classes can become very complex. +Many developers separate the public interface from the inner workings. +Often, all declarations are decoupled from the implementation via header and source files, but there are some exceptions. +The split between those two might seem arbitrary and the following example can give some guidance. + +```cpp +// A file named robot_flower.h +#if !defined(ROBOT_FLOWER_H) +#define ROBOT_FLOWER_H +#include +namespace robots { + class Flower { + private: + bool needs_water{}; + int size{}; + std::string name{}; + public: + Flower(std::string name, int size = 0); + void give_water() {needs_water = false;} + std::string get_name() {return name;} + int get_size() {return size;} + void start_next_day(); + }; +} +#endif +``` + +```cpp +// A file named robot_flower.cpp +#include "robot_flower.h" +robots::Flower::Flower(std::string name, int size) {this->name = "Robotica " + name; this->size = size;} +void robots::Flower::start_next_day() {if (!needs_water) ++size; needs_water = true;} +``` + +Member variables are usually kept in the header together with the implementation of trivial member functions. +The simple `give_water`, `get_name` and `get_size` functions are so small, that one would not move them into the `.cpp` file. +The constructor and the `start_next_day` functions shall be considered more _complex_ in this example and have thus been moved. +The definitions are prefixed with the namespace `robots` and the class type `Flower`. + ## Include Guards via pragma once You may have noticed the `#pragma once` line in the example header file above. diff --git a/concepts/headers/introduction.md b/concepts/headers/introduction.md index d3bb0e74d..8935a6a99 100644 --- a/concepts/headers/introduction.md +++ b/concepts/headers/introduction.md @@ -13,24 +13,28 @@ Some projects use `.hpp` or skip the extension completely. The definitions are located in a separate `.cpp` file. To reunite both parts, this source file starts by including the respective header file. -If you want to write a library called "myLib", that offers a function "my_func" that returns your favorite number, the files would look like this: +If you want to write a library called "quick_math", that offers a function "super_root" that you want to use often, the files would look like this: ```cpp -// A file named myLib.h +// A file named quick_math.h #pragma once -namespace magic { - int my_func(int a, int b); +namespace quick_math { + double super_root(double x, int n); } ``` ```cpp -// A file named myLib.cpp -#include "myLib.h" -int magic::my_func(int a, int b) { - return 47 * a + 3 * b; +// A file named quick_math.cpp +#include "quick_math.h" +#include +double quick_math::super_root(double x, int n) { + while(n) { x = sqrt(x), --n;} + return x; } ``` +If you need to include another header, that is only needed by the implementation, the respective `#include` line is only needed in the source file. +Everything that is included in the header, is also available in the `.cpp` file, like the `string` library in the example below. Attention: the `;` is needed after the declaration in the header file, but not after the definition in the source file. ~~~~exercism/note @@ -38,8 +42,50 @@ Many C++ exercises on Exercism start with two almost empty files: header and sou You have to check the `*_test.cpp` file to see the names and namespaces of the expected functions to solve the exercise. ~~~~ +## Classes and Headers + +Classes can become very complex. +Many developers separate the public interface from the inner workings. +Often, all declarations are decoupled from the implementation via header and source files, but there are some exceptions. +The split between those two might seem arbitrary and the following example can give some guidance. + +```cpp +// A file named robot_flower.h +#ifndef ROBOT_FLOWER_H +#define ROBOT_FLOWER_H +#include +namespace robots { + class Flower { + private: + bool needs_water{}; + int size{}; + std::string name{}; + public: + Flower(std::string name, int size = 0); + void give_water() {needs_water = false;} + std::string get_name() {return name;} + int get_size() {return size;} + void start_next_day(); + }; +} +#endif +``` + +```cpp +// A file named robot_flower.cpp +#include "robot_flower.h" +robots::Flower::Flower(std::string name, int size) {this->name = "Robotica " + name; this->size = size;} +void robots::Flower::start_next_day() {if (!needs_water) ++size; needs_water = true;} +``` + +Member variables are usually kept in the header together with the implementation of trivial member functions. +The simple `give_water`, `get_name` and `get_size` functions are so small, that one would not move them into the `.cpp` file. +The constructor and the `start_next_day` functions shall be considered more _complex_ in this example and have thus been moved. +The definitions are prefixed with the namespace `robots` and the class type `Flower`. + ## Include Guards You may have noticed the `#pragma once` line in the example header file above. This include guard ensures that the content of the file is included only once during the compilation to avoid errors. -There is another, more complex variation that starts with `#ifndef` which serves the same purpose. +There is another, more complex variation that starts with `#ifndef` and ends with `#endif`. +It serves the same purpose and its usage is shown in the `Flower` class example above. diff --git a/concepts/headers/links.json b/concepts/headers/links.json index b5cbcd9b4..5dcf350be 100644 --- a/concepts/headers/links.json +++ b/concepts/headers/links.json @@ -2,5 +2,9 @@ { "url": "https://learn.microsoft.com/en-us/cpp/cpp/header-files-cpp?view=msvc-170", "description": "Examples and information on header files and include guards" + }, + { + "url": "https://www.learncpp.com/cpp-tutorial/classes-and-header-files/", + "description": "More information about classes in header files" } ] \ No newline at end of file