Commit 4684ad1f authored by CHAMONT David's avatar CHAMONT David
Browse files

Last minute changes

parent ced2cd9a
tmp*
core.*
.ipynb_checkpoints
.vscode
.ionide
.DS_Store
gcm.cache
*.o
*.exe
*.log
tmp*
core.*
.fake
\ No newline at end of file
//
// Modify the class Ref, and only this class, so that
// the call to f(make_ref(j)) modify the value of j,
// while f(i) does not modify i.
// The final display should be : 0 42
//
#include <iostream>
template < typename T >
class Ref
{
public :
Ref( T data ) { data_ = data ; }
void operator=( T data ) { data_ = data ; }
private :
T data_ ;
} ;
template < typename T >
Ref<T> make_ref( T & data )
{ return Ref<T>(data) ; }
template < typename T >
void f( T data )
{ data = 42 ; }
int main()
{
int i = 0, j = 0 ;
f(i) ;
f(make_ref(j)) ;
std::cout<<i<<" "<<j<<std::endl ;
return 0 ;
}
......@@ -6,17 +6,15 @@
```cpp
#include <iostream>
struct MyInteger
{
struct MyInteger {
MyInteger( int i = 0 ) : i_(i) {}
int i_ ;
}
}
int main()
{
int main() {
MyInteger mi() ;
std::cout<<mi.i_<<std::endl ;
}
}
```
1. nothing, it will fails to compile MyInteger
......@@ -38,14 +36,13 @@ int main()
## May I copy such an array ?
```cpp
class Array
{
public :
explicit Array( unsigned s ) { data_ = new double [s]; }
double & operator[]( unsigned i ) { return data_[i]; }
~Array() { delete data_; }
private :
double * data_;
class Array {
public :
explicit Array( unsigned s ) { data_ = new double [s]; }
double & operator[]( unsigned i ) { return data_[i]; }
~Array() { delete data_; }
private :
double * data_;
} ;
```
......@@ -145,14 +142,16 @@ bool check()
1. never iterate with a real variable (index)
2. never compare floats with ==
3. 1.0 is a double
4. index value is never 169.0
3. some curly braces are lacking
4. 1.0 is a double
5. index value is never 169.0
## **Good** and *bad* answers
* *1* : one can iterate with anything iterable...
* **2** : floating operation are never perfectly exact ; any floating comparison must allow an epsilon error.
* **3** : because `1.0` is a double, the result of `index / ( index + 1.0 )` is a double, and will not match the value stored in `ref`, which is a float ; try with `1.0f`, or `static_cast<float>( index / ( index + 1.0 ) )`.
* *1* : "never" is a little string, one can iterate with anything iterable, and sometimes need to.
* **2** : as a general rule, floating operation are never perfectly exact ; any floating comparison should allow an epsilon error.
* *3* : some curly braces would make the code more readable, but that is not the issue here.
* **4** : best answer here, because `1.0` is a double, the result of `index / ( index + 1.0 )` is a double, and will not match the value stored in `ref`, which is a float ; try with `1.0f`, or `static_cast<float>( index / ( index + 1.0 ) )`.
* *4* : nice try ;) actually no, because the step of `1.0` is 2 power 0, it can be exactly encoded in binary basis, and the last value of `index` will exactly be `169.0` ; if the step was `0.1`, for example, the value of ìndex` would never be exactly `169.0`.
......@@ -160,15 +159,13 @@ bool check()
## What is lacking below ?
```cpp
class A
{
public :
A() {}
~A() {}
virtual void display() = 0 ;
}
```
class A {\
public :
A() {}
~A() {}
virtual void display() = 0 ;
} ;
1. one "virtual"
2. several "virtual"
......
......@@ -31,7 +31,7 @@
},
{
"cell_type": "code",
"execution_count": 6,
"execution_count": 1,
"metadata": {},
"outputs": [],
"source": [
......@@ -40,7 +40,7 @@
},
{
"cell_type": "code",
"execution_count": 35,
"execution_count": 2,
"metadata": {},
"outputs": [
{
......@@ -99,14 +99,14 @@
},
{
"cell_type": "code",
"execution_count": 2,
"execution_count": 1,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"Overwriting tmp.ref.cpp\n"
"Writing tmp.ref.cpp\n"
]
}
],
......@@ -152,7 +152,7 @@
},
{
"cell_type": "code",
"execution_count": 3,
"execution_count": 2,
"metadata": {},
"outputs": [],
"source": [
......@@ -161,7 +161,7 @@
},
{
"cell_type": "code",
"execution_count": 4,
"execution_count": 3,
"metadata": {},
"outputs": [
{
......@@ -175,6 +175,13 @@
"source": [
"!./tmp.ref.exe"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": []
}
],
"metadata": {
......
......@@ -9,10 +9,11 @@
"We are going to start this review by discussing numerical aspects of C++, because this course is all about scientific computing. Then we'll revise pointers, the major source of errors in C++, as well as C. Next we'll go over some advanced and important points of object-oriented programming. We'll finish the review by discussing templates. This C++ feature can give one a headache but, at the same time, it's one of the language's strong points as evidenced by the standard library. Fasten the belt !\n",
"\n",
"* [Numbers](en.1-numbers.ipynb)\n",
"* [Pointeurs](en.2-pointers.ipynb)\n",
"* [Objects](en.3-objects.ipynb)\n",
"* [Templates](en.4-templates.ipynb)\n",
"* [Specialization](en.5-specialization.ipynb)"
"* [Floating point numbers](en.2-floats.ipynb)\n",
"* [Classes and objects](en.3-objects.ipynb)\n",
"* [Pointers and dynamic memory management](en.4-pointers.ipynb)\n",
"* [Templates](en.5-templates.ipynb)\n",
"* [Templates specialisation](en.6-specialisation.ipynb)"
]
}
],
......
This diff is collapsed.
......@@ -26,10 +26,10 @@
},
{
"cell_type": "code",
"execution_count": null,
"execution_count": 1,
"metadata": {
"slideshow": {
"slide_type": "subslide"
"slide_type": "skip"
}
},
"outputs": [],
......@@ -39,7 +39,7 @@
},
{
"cell_type": "code",
"execution_count": null,
"execution_count": 2,
"metadata": {
"slideshow": {
"slide_type": "fragment"
......@@ -56,7 +56,7 @@
},
{
"cell_type": "code",
"execution_count": null,
"execution_count": 3,
"metadata": {
"slideshow": {
"slide_type": "fragment"
......@@ -73,13 +73,23 @@
},
{
"cell_type": "code",
"execution_count": null,
"execution_count": 4,
"metadata": {
"slideshow": {
"slide_type": "fragment"
}
},
"outputs": [],
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"Base::function1\n",
"Derived::function2\n",
"Derived::function3\n"
]
}
],
"source": [
"Derived obj ;\n",
"obj.function1() ;\n",
......@@ -102,7 +112,7 @@
},
{
"cell_type": "code",
"execution_count": null,
"execution_count": 5,
"metadata": {
"slideshow": {
"slide_type": "subslide"
......@@ -119,7 +129,7 @@
},
{
"cell_type": "code",
"execution_count": null,
"execution_count": 6,
"metadata": {
"slideshow": {
"slide_type": "fragment"
......@@ -136,13 +146,38 @@
},
{
"cell_type": "code",
"execution_count": null,
"execution_count": 7,
"metadata": {
"slideshow": {
"slide_type": "fragment"
}
},
"outputs": [],
"outputs": [
{
"name": "stderr",
"output_type": "stream",
"text": [
"\u001b[1minput_line_13:3:7: \u001b[0m\u001b[0;1;31merror: \u001b[0m\u001b[1mcall to member function 'display' is ambiguous\u001b[0m\n",
" obj.display(42) ;\n",
"\u001b[0;1;32m ~~~~^~~~~~~\n",
"\u001b[0m\u001b[1minput_line_12:3:8: \u001b[0m\u001b[0;1;30mnote: \u001b[0mcandidate function\u001b[0m\n",
" void display( float ) { std::cout<<\"Derived::display( float \"<<std::endl ; }\n",
"\u001b[0;1;32m ^\n",
"\u001b[0m\u001b[1minput_line_12:4:8: \u001b[0m\u001b[0;1;30mnote: \u001b[0mcandidate function\u001b[0m\n",
" void display( double ) { std::cout<<\"Derived::display( double )\"<<std::endl ; }\n",
"\u001b[0;1;32m ^\n",
"\u001b[0m"
]
},
{
"ename": "Interpreter Error",
"evalue": "",
"output_type": "error",
"traceback": [
"Interpreter Error: "
]
}
],
"source": [
"void check( Derived obj )\n",
" { \n",
......@@ -174,7 +209,7 @@
}
},
"source": [
"In the previous example, the compiler frst select the `Derived` class, then hesitate to convert its `int` argument into either a `float` or a `double`."
"In the previous example, the compiler first select the `Derived` class, then hesitate to convert its `int` argument into either a `float` or a `double`."
]
},
{
......@@ -185,7 +220,7 @@
}
},
"source": [
"### Good practice\n",
"### Good old-fashioned practice\n",
"\n",
"When you redefine an inherited member function, **redefine all the base class functions which share the same name**, or you will hide some of them."
]
......@@ -205,10 +240,10 @@
},
{
"cell_type": "code",
"execution_count": null,
"execution_count": 8,
"metadata": {
"slideshow": {
"slide_type": "subslide"
"slide_type": "skip"
}
},
"outputs": [],
......@@ -218,10 +253,10 @@
},
{
"cell_type": "code",
"execution_count": null,
"execution_count": 9,
"metadata": {
"slideshow": {
"slide_type": "-"
"slide_type": "subslide"
}
},
"outputs": [],
......@@ -235,7 +270,7 @@
},
{
"cell_type": "code",
"execution_count": null,
"execution_count": 10,
"metadata": {
"slideshow": {
"slide_type": "fragment"
......@@ -252,13 +287,38 @@
},
{
"cell_type": "code",
"execution_count": null,
"execution_count": 11,
"metadata": {
"slideshow": {
"slide_type": "fragment"
}
},
"outputs": [],
"outputs": [
{
"name": "stderr",
"output_type": "stream",
"text": [
"\u001b[1minput_line_17:5:8: \u001b[0m\u001b[0;1;31merror: \u001b[0m\u001b[1mcall to member function 'display' is ambiguous\u001b[0m\n",
" obj->display(3.14) ;\n",
"\u001b[0;1;32m ~~~~~^~~~~~~\n",
"\u001b[0m\u001b[1minput_line_15:3:16: \u001b[0m\u001b[0;1;30mnote: \u001b[0mcandidate function\u001b[0m\n",
" virtual void display( int ) { std::cout<<\"Base::display( int )\"<<std::endl ; }\n",
"\u001b[0;1;32m ^\n",
"\u001b[0m\u001b[1minput_line_15:4:16: \u001b[0m\u001b[0;1;30mnote: \u001b[0mcandidate function\u001b[0m\n",
" virtual void display( float ) { std::cout<<\"Base::display( float )\"<<std::endl ; }\n",
"\u001b[0;1;32m ^\n",
"\u001b[0m"
]
},
{
"ename": "Interpreter Error",
"evalue": "",
"output_type": "error",
"traceback": [
"Interpreter Error: "
]
}
],
"source": [
"void check( Base * obj )\n",
" {\n",
......@@ -287,14 +347,14 @@
}
},
"source": [
"### Good practice\n",
"### Good old-fashioned practice\n",
"\n",
"When you define a base class with virtual functions, overload those functions for all the type of arguments that you expect in the derived classes."
"When you define a base class with virtual functions, overload those functions for all the expected type of arguments that you expect in the derived classes."
]
},
{
"cell_type": "code",
"execution_count": null,
"execution_count": 12,
"metadata": {
"slideshow": {
"slide_type": "-"
......@@ -318,7 +378,7 @@
}
},
"source": [
"### Other good practice\n",
"### Other good old-fashioned practice\n",
"\n",
"**Make the destructor `virtual`**. Indeed, you may create a derived object with `new` and store its address in a base class pointer. When calling `delete` on this pointer, one will bypass the derived destructor, unless it is virtual."
]
......@@ -385,7 +445,7 @@
}
},
"source": [
"### The use of virtual functions\n",
"### The recommended use of virtual functions\n",
"\n",
"Because of the cost, virtual functions are rather used for large and not numerous objects : the upper software layers of your application. For what concerns the numerous and small objects, it is preferable to use templates (which slow down the compilation but have not effect during execution)."
]
......@@ -405,10 +465,10 @@
},
{
"cell_type": "code",
"execution_count": null,
"execution_count": 13,
"metadata": {
"slideshow": {
"slide_type": "subslide"
"slide_type": "skip"
}
},
"outputs": [],
......@@ -418,10 +478,10 @@
},
{
"cell_type": "code",
"execution_count": null,
"execution_count": 22,
"metadata": {
"slideshow": {
"slide_type": "-"
"slide_type": "subslide"
}
},
"outputs": [],
......@@ -429,22 +489,30 @@
"class LinearFunction\n",
" {\n",
" public :\n",
" LinearFunction( double constant ) : constant_(constant) {}\n",
" double operator()( double value ) { return constant_*value ; }\n",
" LinearFunction( double constant ) : m_constant(constant) {}\n",
" double operator()( double value ) { return m_constant*value ; }\n",
" private :\n",
" double constant_ ; \n",
" double m_constant ; \n",
" } ;"
]
},
{
"cell_type": "code",
"execution_count": null,
"execution_count": 23,
"metadata": {
"slideshow": {
"slide_type": "-"
}
},
"outputs": [],
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"0 2 4 6 8 10 12 14 16 18 "
]
}
],
"source": [
"LinearFunction times2(2) ;\n",
"const int SIZE = 10 ;\n",
......@@ -461,7 +529,7 @@
}
},
"source": [
"### The use of function-objects\n",
"### The recommended use of function-objects\n",
"\n",
"This type of classes is especially used with algorithms of the standard library."
]
......@@ -479,10 +547,10 @@
},
{
"cell_type": "code",
"execution_count": null,
"execution_count": 16,
"metadata": {
"slideshow": {
"slide_type": "-"
"slide_type": "skip"
}
},
"outputs": [],
......@@ -492,7 +560,7 @@
},
{
"cell_type": "code",
"execution_count": null,
"execution_count": 24,
"metadata": {
"slideshow": {
"slide_type": "-"
......@@ -504,23 +572,31 @@
"\n",
" {\n",
" public :\n",
" LinearFunctionPrint( double constant ) : constant_(constant) {}\n",
" LinearFunctionPrint( double constant ) : m_constant(constant) {}\n",
" void operator()( double value )\n",
" { std::cout << (constant_*value) << \" \" ; }\n",
" { std::cout << (m_constant*value) << \" \" ; }\n",
" private :\n",
" double constant_ ; \n",
" double m_constant ; \n",
" } ;"
]
},
{
"cell_type": "code",
"execution_count": null,
"execution_count": 25,
"metadata": {
"slideshow": {
"slide_type": "-"
}
},
"outputs": [],
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"0 2 4 6 8 10 12 14 16 18 "
]
}
],
"source": [
"const int SIZE = 10 ;\n",
"double values[SIZE] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 } ;\n",
......@@ -540,7 +616,7 @@
},
{
"cell_type": "code",
"execution_count": null,
"execution_count": 20,
"metadata": {
"slideshow": {
"slide_type": "-"
......@@ -549,7 +625,6 @@
"outputs": [],
"source": [
"class LinearFunctionPrint : public LinearFunction\n",
"\n",
" {\n",
" public :\n",
" LinearFunctionPrint( double constant ) : LinearFunction(constant) {}\n",
......@@ -560,13 +635,21 @@
},
{
"cell_type": "code",
"execution_count": null,
"execution_count": 21,
"metadata": {
"slideshow": {
"slide_type": "-"
}