diff --git a/2-ObjectProgramming/1-Introduction.ipynb b/2-ObjectProgramming/1-Introduction.ipynb index 6131f5256e13fb8baa3cf894062667bf20d09a9f..61f13b800cffd1f7db856676c500994670d4ec6b 100644 --- a/2-ObjectProgramming/1-Introduction.ipynb +++ b/2-ObjectProgramming/1-Introduction.ipynb @@ -40,7 +40,7 @@ "#include <iostream>\n", "#include <cmath> // For std::sqrt\n", "\n", - "double norm(double v_x, double v_y, double v_z) \n", + "double Norm(double v_x, double v_y, double v_z) \n", "{ \n", " return std::sqrt( v_x * v_x + v_y * v_y + v_z * v_z ); \n", "}\n", @@ -51,14 +51,14 @@ " v1_y = 5.;\n", " v1_z = -2.;\n", "\n", - " std::cout << norm(v1_x, v1_y, v1_z) << std::endl;\n", + " std::cout << Norm(v1_x, v1_y, v1_z) << std::endl;\n", "\n", " double v2_x, v2_y, v2_z;\n", " v2_x = 2.;\n", " v2_y = 2.;\n", " v2_z = 4.;\n", "\n", - " std::cout << norm(v2_x, v2_y, v2_z) << std::endl;\n", + " std::cout << Norm(v2_x, v2_y, v2_z) << std::endl;\n", "}\n" ] }, @@ -66,7 +66,7 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "The code above is completely oblivious of the close relationship between `x`, `y` and `z`, and for instance the norm function takes three distinct arguments. \n", + "The code above is completely oblivious of the close relationship between `x`, `y` and `z`, and for instance the `Norm` function takes three distinct arguments. \n", "\n", "This is not just an inconveniency: this can lead to mistake if there is an error in the variables passed:" ] @@ -87,7 +87,7 @@ " v2_y = 2.;\n", " v2_z = 4.;\n", "\n", - " const double norm1 = norm(v1_x, v1_y, v2_z); // probably not what was intended, but the program \n", + " const double norm1 = Norm(v1_x, v1_y, v2_z); // probably not what was intended, but the program \n", " // has no way to figure out something is fishy!\n", "}" ] @@ -123,7 +123,7 @@ "source": [ "#include <iostream>\n", "\n", - "double norm(Vector v)\n", + "double Norm(Vector v)\n", "{\n", " return std::sqrt(v.x * v.x + v.y * v.y + v.z * v.z); \n", "}\n", @@ -134,14 +134,14 @@ " v1.y = 5.;\n", " v1.z = -2.;\n", "\n", - " std::cout << norm(v1) << std::endl;\n", + " std::cout << Norm(v1) << std::endl;\n", "\n", " Vector v2;\n", " v2.x = 2.;\n", " v2.y = 2.;\n", " v2.z = 4.;\n", "\n", - " std::cout << norm(v2) << std::endl; \n", + " std::cout << Norm(v2) << std::endl; \n", "}" ] }, @@ -149,7 +149,7 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "Calling `norm` is now both more elegant (only one argument) and less dangerous (I can't mix by mistake coordinates from different objects).\n", + "Calling `Norm` is now both more elegant (only one argument) and less dangerous (I can't mix by mistake coordinates from different objects).\n", "\n", "Let's introduce at this point a bit of vocabulary:\n", "\n", @@ -174,9 +174,9 @@ "metadata": {}, "outputs": [], "source": [ - "// Xeus-cling issue (at least circa May 2021)\n", + "// Xeus-cling issue (at least circa September 2022)\n", "\n", - "struct Vector\n", + "struct VectorAndInstantiate\n", "{\n", " double x;\n", " double y;\n", @@ -219,7 +219,7 @@ "metadata": {}, "outputs": [], "source": [ - "double norm_without_copy(const Vector& v)\n", + "double NormWithoutCopy(const Vector& v)\n", "{\n", " return std::sqrt(v.x * v.x + v.y * v.y + v.z * v.z); \n", "}\n", @@ -230,7 +230,7 @@ " v1.y = 5.;\n", " v1.z = -2.;\n", "\n", - " std::cout << norm_without_copy(v1) << std::endl;\n", + " std::cout << NormWithoutCopy(v1) << std::endl;\n", "}" ] }, @@ -249,7 +249,7 @@ "metadata": {}, "outputs": [], "source": [ - "double norm(const Vector* const v) // can keep the name here: no possible ambiguity\n", + "double Norm(const Vector* const v) // can keep the name here: no possible ambiguity\n", "{\n", " return std::sqrt((*v).x * (*v).x + (*v).y * (*v).y + (*v).z * (*v).z); \n", "}\n", @@ -260,7 +260,7 @@ " v1.y = 5.;\n", " v1.z = -2.;\n", "\n", - " std::cout << norm(&v1) << std::endl;\n", + " std::cout << Norm(&v1) << std::endl;\n", "}" ] }, @@ -277,7 +277,7 @@ "metadata": {}, "outputs": [], "source": [ - "double norm_with_pointer_shortcut(const Vector* const v)\n", + "double NormWithPointerShortcut(const Vector* const v)\n", "{\n", " return std::sqrt(v->x * v->x + v->y * v->y + v->z * v->z); \n", "}\n", @@ -288,7 +288,7 @@ " v1.y = 5.;\n", " v1.z = -2.;\n", "\n", - " std::cout << norm_with_pointer_shortcut(&v1) << std::endl;\n", + " std::cout << NormWithPointerShortcut(&v1) << std::endl;\n", "}" ] }, @@ -298,7 +298,7 @@ "source": [ "## Initialization of objects\n", "\n", - "So far, we have improved the way the `norm` function is called, but the initialization of a vector is still a bit tedious. Let's wrap up a function to ease that:" + "So far, we have improved the way the `Norm` function is called, but the initialization of a vector is still a bit tedious. Let's wrap up a function to ease that:" ] }, { @@ -307,7 +307,7 @@ "metadata": {}, "outputs": [], "source": [ - "void init(Vector& v, double x, double y, double z) \n", + "void Init(Vector& v, double x, double y, double z) \n", "{\n", " v.x = x;\n", " v.y = y;\n", @@ -323,8 +323,8 @@ "source": [ "{\n", " Vector v1;\n", - " init(v1, 1., 5., -2.);\n", - " std::cout << \"Norm = \" << norm(v1) << std::endl;\n", + " Init(v1, 1., 5., -2.);\n", + " std::cout << \"Norm = \" << Norm(v1) << std::endl;\n", "}" ] }, diff --git a/2-ObjectProgramming/2-Member-functions.ipynb b/2-ObjectProgramming/2-Member-functions.ipynb index d4b18875766d119ff41146afc5d545325504f83b..5553433ef612170b473db0d804eb7fbbef7c093c 100644 --- a/2-ObjectProgramming/2-Member-functions.ipynb +++ b/2-ObjectProgramming/2-Member-functions.ipynb @@ -25,7 +25,7 @@ "\n", "The struct we used previously would work the same in C code (with the exceptions of references: with a C compiler you would have to stick with pointers).\n", "\n", - "But when Bjarne Stroustrup created the C++, its main idea was to extend these structs into full-fledged **classes** (to the point the work name of his language was *C with classes*...)\n", + "But when Bjarne Stroustrup created the C++, its main idea was to extend these structs into full-fledged **classes** (to the point the working name of his language was *C with classes*...)\n", "\n", "One of the idea that was missing with original C `struct` was the possibility to add as well member functions:" ] @@ -44,14 +44,14 @@ " double y; \n", " double z;\n", " \n", - " void init(double x, double y, double z)\n", + " void Init(double x, double y, double z)\n", " {\n", " this->x = x;\n", " this->y = y;\n", " this->z = z;\n", " }\n", " \n", - " double norm()\n", + " double Norm()\n", " {\n", " return std::sqrt(x * x + y * y + z * z);\n", " }\n", @@ -69,8 +69,8 @@ "\n", "{\n", " Vector v;\n", - " v.init(5., 6., -4.2);\n", - " std::cout << v.norm() << std::endl;\n", + " v.Init(5., 6., -4.2);\n", + " std::cout << v.Norm() << std::endl;\n", "}" ] }, @@ -80,7 +80,7 @@ "source": [ "Let's do a bit of taxonomy here:\n", "\n", - "- `init()` and `norm()` are called **member functions** or **methods**. The same remark concerning C++ purist I did for member variables may be applied here.\n", + "- `Init()` and `Norm()` are called **member functions** or **methods**. The same remark concerning C++ purist I did for member variables may be applied here.\n", "- **Method** is used in other programming languages, but for some reason Julia creators used this exact term for an entirely different concept. So to put in a nutshell a C++ method is akin to a Python one but not to what Julia calls a method.\n", "- **Attributes** are in fact the data attributes AND the methods. It is however often used only to designate the data attributes.\n", "\n", @@ -93,9 +93,9 @@ "source": [ "## The `this` keyword\n", "\n", - "The `this->` may have puzzled you: it is a keyword to refer to the current object. So when you call `v.init(...)`, this is an implicit reference to `v`.\n", + "The `this->` may have puzzled you: it is a keyword to refer to the current object. So when you call `v.Init(...)`, this is an implicit reference to `v`.\n", "\n", - "In most cases, it might be altogether removed; we have to put it explicitly here solely because we named the `init` parameters with the same name as the data attribute. If not, we could have avoided to mention it completely.\n", + "In most cases, it might be altogether removed; we have to put it explicitly here solely because we named the `Init` parameters with the same name as the data attribute. If not, we could have avoided to mention it completely.\n", "\n", "An usual convention is to suffix data attributes with a `_` (**be careful**, attributes prefixed with a `_` is reserved by the C++ standard); doing so remove the need to the explicit `this`:" ] @@ -114,14 +114,14 @@ " double y_; \n", " double z_;\n", " \n", - " void init(double x, double y, double z)\n", + " void Init(double x, double y, double z)\n", " {\n", - " x_ = x;\n", + " x_ = x; // no need to `this`here as there is no ambiguity between data attribute name and parameter name\n", " y_ = y;\n", " z_ = z;\n", " }\n", " \n", - " double norm()\n", + " double Norm()\n", " {\n", " return std::sqrt(x_ * x_ + y_ * y_ + z_ * z_);\n", " }\n", @@ -139,8 +139,8 @@ "\n", "{\n", " Vector2 v;\n", - " v.init(5., 6., -4.2);\n", - " std::cout << v.norm() << std::endl;\n", + " v.Init(5., 6., -4.2);\n", + " std::cout << v.Norm() << std::endl;\n", "}" ] }, @@ -157,9 +157,9 @@ "source": [ "## Separating declaration and definition\n", "\n", - "We have defined above the method directly in the class declaration; which is not very clean. It is acceptable for a very short method as here, but for a more complex class and method it is better to separate explicitly both. In this case you will have:\n", + "We have defined so far the method directly in the class declaration; which is not very clean. It is acceptable for a very short method as here, but for a more complex class and method it is better to separate explicitly both. In this case you will have:\n", "\n", - "- On one side, usually in a header file:\n" + "- On one side, usually in a header file (we'll see the file structure in real C++ code [later on](../6-InRealEnvironment/2-FileStructure.ipynb)):\n" ] }, { @@ -174,9 +174,9 @@ " double y_; \n", " double z_;\n", " \n", - " void init(double x, double y, double z);\n", + " void Init(double x, double y, double z);\n", " \n", - " double norm();\n", + " double Norm();\n", "};" ] }, @@ -193,7 +193,7 @@ "metadata": {}, "outputs": [], "source": [ - "void Vector3::init(double x, double y, double z)\n", + "void Vector3::Init(double x, double y, double z)\n", "{\n", " x_ = x;\n", " y_ = y;\n", @@ -207,7 +207,7 @@ "metadata": {}, "outputs": [], "source": [ - "double Vector3::norm()\n", + "double Vector3::Norm()\n", "{\n", " return std::sqrt(x_ * x_ + y_ * y_ + z_ * z_);\n", "}" @@ -223,8 +223,8 @@ "\n", "{\n", " Vector3 v;\n", - " v.init(5., 6., -4.2);\n", - " std::cout << v.norm() << std::endl;\n", + " v.Init(5., 6., -4.2);\n", + " std::cout << v.Norm() << std::endl;\n", "}" ] }, @@ -254,9 +254,9 @@ "source": [ "#include <iostream>\n", "\n", - "void print_norm(const Vector3& v)\n", + "void PrintNorm(const Vector3& v)\n", "{\n", - " std::cout << v.norm() << std::endl;\n", + " std::cout << v.Norm() << std::endl; // COMPILATION ERROR\n", "}" ] }, @@ -266,7 +266,7 @@ "source": [ "... we see that doesn't compile. So what is happening?\n", "\n", - "The issue here is that the function `print_norm` takes as argument a constant reference, and has to guarantee the underlying object is not modified in the process. A \"patch\" would be to define it without the const:\n", + "The issue here is that the function `PrintNorm` takes as argument a constant reference, and has to guarantee the underlying object is not modified in the process. A \"patch\" would be to define it without the const:\n", "\n" ] }, @@ -278,9 +278,9 @@ "source": [ "#include <iostream>\n", "\n", - "void print_norm_no_const(Vector3& v) // BAD IDEA!\n", + "void PrintNormNoConst(Vector3& v) // BAD IDEA!\n", "{\n", - " std::cout << v.norm() << std::endl;\n", + " std::cout << v.Norm() << std::endl;\n", "}" ] }, @@ -292,8 +292,8 @@ "source": [ "{\n", " Vector3 v;\n", - " v.init(5., 6., -4.2);\n", - " print_norm_no_const(v);\n", + " v.Init(5., 6., -4.2);\n", + " PrintNormNoConst(v);\n", "}" ] }, @@ -303,9 +303,9 @@ "source": [ "Why is it such a poor idea? C++ is a compiled language, and this has its (many) pros and (many) cons. One of the advantages is to be able to leverage the compilation to detect at early time something is amiss. Here the compilation error is a good way to see we might be doing something wrong.\n", "\n", - "The sketchy \"patch\" I provided would be akin to ignoring the `const` feature almost entirely when objects are concerned.\n", + "The sketchy \"patch\" I provided would be akin to ignoring the `const` feature almost entirely whenever objects are concerned.\n", "\n", - "The proper way is in fact quite the opposite: we may specify when writing a method that it is not allowed to modify the state of the object:" + "The proper way to solve the issue is in fact quite the opposite: we may specify when writing a method that it is not allowed to modify the state of the object:" ] }, { @@ -320,11 +320,11 @@ " double y_; \n", " double z_;\n", " \n", - " void init(double x, double y, double z);\n", + " void Init(double x, double y, double z);\n", " \n", - " double norm() const; // notice the additional keyword!\n", + " double Norm() const; // notice the additional keyword!\n", " \n", - " void dont_put_const_everywhere() const;\n", + " void DontPutConstEverywhere() const;\n", "};" ] }, @@ -334,7 +334,7 @@ "metadata": {}, "outputs": [], "source": [ - "void Vector4::init(double x, double y, double z)\n", + "void Vector4::Init(double x, double y, double z)\n", "{\n", " x_ = x;\n", " y_ = y;\n", @@ -348,7 +348,7 @@ "metadata": {}, "outputs": [], "source": [ - "double Vector4::norm() const\n", + "double Vector4::Norm() const\n", "{\n", " return std::sqrt(x_ * x_ + y_ * y_ + z_ * z_);\n", "}" @@ -369,15 +369,15 @@ "source": [ "#include <iostream>\n", "\n", - "void print_norm(const Vector4& v)\n", + "void PrintNorm(const Vector4& v)\n", "{\n", - " std::cout << v.norm() << std::endl;\n", + " std::cout << v.Norm() << std::endl;\n", "}\n", "\n", "{\n", " Vector4 v;\n", - " v.init(5., 6., -4.2);\n", - " print_norm(v);\n", + " v.Init(5., 6., -4.2);\n", + " PrintNorm(v);\n", "}" ] }, @@ -394,7 +394,7 @@ "metadata": {}, "outputs": [], "source": [ - "void Vector4::dont_put_const_everywhere() const\n", + "void Vector4::DontPutConstEverywhere() const\n", "{\n", " x_ = 0.; // ERROR!\n", "}" @@ -422,9 +422,9 @@ " double z_;\n", " mutable unsigned int Nnorm_calls_;\n", " \n", - " void init(double x, double y, double z);\n", + " void Init(double x, double y, double z);\n", " \n", - " double norm() const; \n", + " double Norm() const; \n", "};" ] }, @@ -434,7 +434,7 @@ "metadata": {}, "outputs": [], "source": [ - "void Vector5::init(double x, double y, double z)\n", + "void Vector5::Init(double x, double y, double z)\n", "{\n", " x_ = x;\n", " y_ = y;\n", @@ -449,7 +449,7 @@ "metadata": {}, "outputs": [], "source": [ - "double Vector5::norm() const\n", + "double Vector5::Norm() const\n", "{\n", " ++Nnorm_calls_;\n", " return std::sqrt(x_ * x_ + y_ * y_ + z_ * z_);\n", @@ -462,12 +462,14 @@ "metadata": {}, "outputs": [], "source": [ + "#include <iostream>\n", + "\n", "{\n", " Vector5 v;\n", - " v.init(5., 6., -4.2);\n", + " v.Init(5., 6., -4.2);\n", " for (int i = 0; i < 5; ++i)\n", - " v.norm();\n", - " std::cout << \"Method 'norm()' was called \" << v.Nnorm_calls_ << \" times.\" << std::endl; \n", + " v.Norm();\n", + " std::cout << \"Method 'Norm()' was called \" << v.Nnorm_calls_ << \" times.\" << std::endl; \n", "}" ] }, diff --git a/2-ObjectProgramming/3-constructors-destructor.ipynb b/2-ObjectProgramming/3-constructors-destructor.ipynb index ced0b1d2f74da0a198825d98467ce46379acfe72..c2a257ef8c72bceac872977d1e7956d9591d1219 100644 --- a/2-ObjectProgramming/3-constructors-destructor.ipynb +++ b/2-ObjectProgramming/3-constructors-destructor.ipynb @@ -23,7 +23,7 @@ "source": [ "## Introduction to base constructor\n", "\n", - "In fact, our previous `init()` function is meant to be realized through a dedicated method called a **constructor**. By convention, a constructor shares the name of the struct or class.\n", + "In fact, our previous `Init()` function is meant to be realized through a dedicated method called a **constructor**. By convention, a constructor shares the name of the struct or class.\n", "\n", "Several constructors may be defined for a given class, provided there is no signature overlap." ] @@ -44,7 +44,7 @@ " \n", " Vector(double x, double y, double z); // Another constructor\n", " \n", - " double norm() const;\n", + " double Norm() const;\n", "};" ] }, @@ -88,7 +88,7 @@ "metadata": {}, "outputs": [], "source": [ - "double Vector::norm() const\n", + "double Vector::Norm() const\n", "{\n", " return std::sqrt(x_ * x_ + y_ * y_ + z_ * z_);\n", "}" @@ -104,7 +104,7 @@ "\n", "{\n", " Vector v(5., 6., -4.2); // note the creation of an object with a constructor call.\n", - " std::cout << v.norm() << std::endl;\n", + " std::cout << v.Norm() << std::endl;\n", "}" ] }, @@ -127,7 +127,7 @@ "\n", "{\n", " Vector v; // no parenthesis here!\n", - " std::cout << v.norm() << std::endl;\n", + " std::cout << v.Norm() << std::endl;\n", "}" ] }, @@ -150,7 +150,7 @@ "\n", "{\n", " auto v = Vector(5, 10, 15); // auto-to-stick syntax: a new perfectly fine way to declare an object.\n", - " std::cout << v.norm() << std::endl;\n", + " std::cout << v.Norm() << std::endl;\n", "}" ] }, @@ -169,7 +169,7 @@ "source": [ "{\n", " auto v = Vector(); // auto-to-stick syntax\n", - " std::cout << v.norm() << std::endl; \n", + " std::cout << v.Norm() << std::endl; \n", "}" ] }, @@ -182,39 +182,13 @@ "I advise you to read this very interesting [FluentCpp post](https://www.fluentcpp.com/2018/09/28/auto-stick-changing-style/) about this syntax which ponders about the relunctance we might have to embrace evolution of our languages - so the reading is of interest even for developers using other languages." ] }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "### \"braces\" (`{}`) for constructor calls\n", - "\n", - "Another alternate syntax that removes the ambiguity is the use of braces (`{}`):" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "#include <iostream>\n", - "\n", - "{\n", - " Vector v1{}; // Constructor Vector()\n", - " std::cout << v1.norm() << std::endl;\n", - "\n", - " Vector v2{5., 6., -4.2}; // The other constructor Vector(double x, double y, double z)\n", - " std::cout << v2.norm() << std::endl;\n", - "}" - ] - }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Initializing a reference data attribute\n", "\n", - "We saw above a new syntax to initialize data attributes, but there is no harm defining the same as we did in our former `init()` method. That is however not true when there is a reference data attribute, for which the reference must absolutely be defined with the new syntax:" + "We saw above a new syntax to initialize data attributes, but there is no harm defining the same as we did in our former `Init()` method. That is however not true when there is a reference data attribute, for which the reference must absolutely be defined with the new syntax:" ] }, { @@ -447,7 +421,7 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "This must seem messy at first sight, but doing otherwise would be nightmarish: if you define a very complex class that must be carefully initialized with well thought-out arguments, you do not want your end-user to bypass this with a inconsiderate call to a constructor without arguments!\n", + "This must seem messy at first sight, but doing otherwise would be nightmarish: if you define a very complex class that must be carefully initialized with well thought-out arguments, you do not want your end-user to bypass this with an inconsiderate call to a constructor without arguments!\n", "\n", "If you want to enable back constructor without arguments, you may do so by defining it explicitly. C++11 introduced a nice way to do so (provided you wish an empty body - if not define it explicitly yourself):" ] diff --git a/2-ObjectProgramming/4-encapsulation.ipynb b/2-ObjectProgramming/4-encapsulation.ipynb index 217c6386351f100d3b3751462f65ad301fbe0d5b..983115c5f8bff8699e41cdf66750c27d5234f05a 100644 --- a/2-ObjectProgramming/4-encapsulation.ipynb +++ b/2-ObjectProgramming/4-encapsulation.ipynb @@ -727,7 +727,7 @@ " \n", " Vector(double x, double y, double z);\n", " \n", - " friend double norm(const Vector&);\n", + " friend double Norm(const Vector&);\n", " \n", " friend class PrintVector; // In C++11 `class` became optional here.\n", " \n", @@ -760,7 +760,7 @@ "source": [ "#include <cmath>\n", "\n", - "double norm(const Vector& v)\n", + "double Norm(const Vector& v)\n", "{\n", " return std::sqrt(v.x_ * v.x_ + v.y_ * v.y_ + v.z_ * v.z_); // OK!\n", "}" @@ -831,7 +831,7 @@ "Obviously, friendship should be used with parsimony... But it's not that much of a deal-breaker as it may seem:\n", "\n", "* The friendship must be defined in the class declaration. It means you can't use it to bypass a class encapsulation without modifying this code directly.\n", - "* The friendship is granted to a very specific function or class, and this class must be known when the class is defined. So an ill-intentioned user can't use the function prototype to sneak into your class private parts (in fact [forward declaration](../6-InRealEnvironment/2-FileStructure.ipynb#Forward-declaration) is an exception to current statement)." + "* The friendship is granted to a very specific function or class, and this class must be known when the class is defined. So an ill-intentioned user can't use the function prototype to sneak into your class private parts (in fact to be completely honest we will see an exception to this statement later with [forward declaration](../6-InRealEnvironment/2-FileStructure.ipynb#Forward-declaration))." ] }, { diff --git a/2-ObjectProgramming/5-static.ipynb b/2-ObjectProgramming/5-static.ipynb index d11c49f9b020004cf1ecc0cbf80f40eb2e43de61..5d1c41649b95935bcdea5403c019191ee322fbca 100644 --- a/2-ObjectProgramming/5-static.ipynb +++ b/2-ObjectProgramming/5-static.ipynb @@ -39,7 +39,7 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "Sometimes, a data is related to the _class_ itself rather than to the object. The way to indicate this is to put a **static** keyword in front of the attribute that is not especially related to the instantiated object but rather common to all instances.\n", + "Sometimes, a data is related to the _class_ itself rather than to the object. The way to indicate this is to put a `static` keyword in front of the attribute that is not especially related to the instantiated object but rather common to all instances.\n", "\n", "Static attributes are following the exact same rules as the standard ones regarding the access status (public or private)." ] @@ -118,7 +118,7 @@ " \n", " ~Class();\n", " \n", - " static int Ninstance_;\n", + " static unsigned int Ninstance_;\n", "};\n", "\n", "Class::Class()\n", @@ -132,7 +132,7 @@ "}\n", "\n", "// IMPORTANT: this line must be put in a compiled file!\n", - "int Class::Ninstance_ = 0;\n", + "unsigned int Class::Ninstance_ = 0;\n", "\n", "void Print()\n", "{\n", @@ -183,7 +183,7 @@ " \n", " ~Class3();\n", " \n", - " static int& Ninstance(); // notice the reference and the fact it's now a method\n", + " static unsigned int& Ninstance(); // notice the reference and the fact it's now a method\n", "};" ] }, @@ -193,9 +193,9 @@ "metadata": {}, "outputs": [], "source": [ - "int& Class3::Ninstance()\n", + "unsigned int& Class3::Ninstance()\n", "{\n", - " static int ret = 0; // the initial value, please notice the use of C static here!\n", + " static unsigned int ret = 0; // the initial value, please notice the use of C static here!\n", " return ret;\n", "}" ] @@ -276,7 +276,7 @@ "source": [ "### New C++ 17 fix\n", "\n", - "C++ 17 actually provides a way to define the value in the header file with the `inline` keyword:" + "C++ 17 actually provides a way to define the value in the header file within the class declaration with the `inline` keyword:" ] }, { @@ -291,7 +291,7 @@ " \n", " ~Class4();\n", " \n", - " static inline int Ninstance_ = 0;\n", + " static inline unsigned int Ninstance_ = 0;\n", "};" ] }, diff --git a/2-ObjectProgramming/6-inheritance.ipynb b/2-ObjectProgramming/6-inheritance.ipynb index 982604c0378ed3e3babef1b932820ff79fb2da7e..ff46ffd10f6ffac07ea38c6e054c9586dab67bae 100644 --- a/2-ObjectProgramming/6-inheritance.ipynb +++ b/2-ObjectProgramming/6-inheritance.ipynb @@ -128,7 +128,7 @@ " \n", "The base class part is constructed first, and then the elements specific to the derived class are added (that will be important - we will come back to that).\n", " \n", - "Likewise, destruction is performed in reverse order: first the specific part of the derived class, then the base class (in most cases you don't have to care about that).\n", + "Likewise, destruction is performed in reverse order: first the specific parts of the derived class, then the base class (in most cases you don't have to care about that).\n", "\n", "### Multiple layer of inheritance\n", "\n", @@ -229,7 +229,7 @@ "source": [ "BlueVehicle::BlueVehicle(motor_type type)\n", ": Vehicle(type), // mandatory call of the non-default constructor \n", - "BlueObjects() // not mandatory: default constructor called\n", + "BlueObjects() // not mandatory: default constructor called anyway if not specified explicitly\n", "{ }" ] }, @@ -755,7 +755,9 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "You may have noticed the data attribute is stored as a pointer: this avoids issues related to the initialization of the object when it uses a non-default constructor. This doesn't mean using directly an object is impossible, just that extra conditions must be fulfilled in this case.\n" + "You may have noticed the data attribute is stored as a pointer: this avoids issues related to the initialization of the object when it uses a non-default constructor (here as `Rectangle` doesn't get a default constructor your compiler would yell if the data attribute was directly a `Rectangle` rather than a pointer). \n", + "\n", + "This doesn't mean using directly an object is impossible, just that extra conditions must be fulfilled in this case.\n" ] }, { diff --git a/2-ObjectProgramming/7-polymorphism.ipynb b/2-ObjectProgramming/7-polymorphism.ipynb index 0eacc5ce9cf78e1a1a6994e0f9c7d23b3f23b2d6..544bf97163581b2c3d741737215f0ef9d067205c 100644 --- a/2-ObjectProgramming/7-polymorphism.ipynb +++ b/2-ObjectProgramming/7-polymorphism.ipynb @@ -410,7 +410,7 @@ " PolymorphicButClumsyVehicle* list[3] = { v, b, c };\n", " \n", " for (auto i = 0ul; i < 3ul; ++i)\n", - " list[i]->Print(); // No compilation error, but clearly not what we intended...\n", + " list[i]->Print();\n", " \n", " delete v;\n", " delete b;\n", @@ -535,6 +535,8 @@ "cell_type": "markdown", "metadata": {}, "source": [ + "_(don't worry if you get a warning - if so the compiler does its job well and we'll see shortly why)_\n", + "\n", "**Beware:** You **must** provide a definition for all non pure-virtual methods in your class. Not doing so leads to a somewhat cryptic error at link-time.\n", "\n", "You are not required to provide a definition for a pure virtual method, and you won't most of the time... But you might provide one if you want to do so, for instance to provide an optional default instantiation for the method in derived classes:" @@ -912,7 +914,7 @@ "source": [ "You may in fact explicitly tells the `c` pointer needs to be interpreted as a `PolymorphicThermicCar`:\n", "\n", - "**Xeus-cling issue:** Here cling may not be able to run it (depends on the version used) but it is accepted rightfully by a full-fledged compiler (see for instance [@Coliru](http://coliru.stacked-crooked.com/a/22fff15d28c93a17)):" + "**Xeus-cling issue:** Here cling may not be able to run it (depends on the version used - it didn't in 2021 but seems to work in 2022) but it is accepted rightfully by a full-fledged compiler (see for instance [@Coliru](http://coliru.stacked-crooked.com/a/22fff15d28c93a17)):" ] }, { @@ -1155,8 +1157,8 @@ "\n", "So to put in a nutshell, 99 % of the time:\n", "\n", - "* If a class of yours is intended to be inherited from, make its destructor virtual.\n", - "* If not, mark it as final.\n" + "* If a class of yours is intended to be inherited from, make its destructor `virtual`.\n", + "* If not, mark the class as `final`.\n" ] }, { @@ -1167,7 +1169,7 @@ "\n", "A very important point: I lost time years ago with this because I didn't read carefully enough item 9 of \\cite{Meyers2005}...\n", "\n", - "Due to the way construction occurs, never call a virtual method in a constructor: it won't perform the dynamic binding as you would like it to.\n", + "Due to the way construction occurs, never call a virtual method in a constructor: it won't perform the dynamic binding as you would like it to (and your compiler won't help you here)\n", "\n" ] },