From 42bf157e43d90928587b0cdfefa4a126be29c1a0 Mon Sep 17 00:00:00 2001 From: vaeng <34183939+vaeng@users.noreply.github.com> Date: Tue, 17 Oct 2023 16:25:08 +0200 Subject: [PATCH 1/2] feat: add class info for headers concept --- concepts/headers/introduction.md | 64 +++++++++++++++++++++++++++----- concepts/headers/links.json | 4 ++ 2 files changed, 59 insertions(+), 9 deletions(-) diff --git a/concepts/headers/introduction.md b/concepts/headers/introduction.md index d3bb0e74d..9a13b7e0a 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 +#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 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 `#if !defined` 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 From 5c34f50195e131dcaa6e557329f54df3e8c48f4a Mon Sep 17 00:00:00 2001 From: vaeng <34183939+vaeng@users.noreply.github.com> Date: Wed, 18 Oct 2023 10:53:24 +0200 Subject: [PATCH 2/2] feat: update class about.md --- concepts/headers/about.md | 61 +++++++++++++++++++++++++++----- concepts/headers/introduction.md | 4 +-- 2 files changed, 55 insertions(+), 10 deletions(-) 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 9a13b7e0a..8935a6a99 100644 --- a/concepts/headers/introduction.md +++ b/concepts/headers/introduction.md @@ -51,7 +51,7 @@ The split between those two might seem arbitrary and the following example can g ```cpp // A file named robot_flower.h -#if !defined(ROBOT_FLOWER_H) +#ifndef ROBOT_FLOWER_H #define ROBOT_FLOWER_H #include namespace robots { @@ -87,5 +87,5 @@ The definitions are prefixed with the namespace `robots` and the class type `Flo 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 `#if !defined` and ends with `#endif`. +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.