Captain's log: week 1
Decided to do my own c++ tutorial to get a better idea of what c++ is and the things we can do with it. I have decided instead to start with those topics that are usually more complex. I will try to explain each of the concepts and give different examples. Going from the theory to real applications.
Notes and Suggestions
Arrays
An array is a fixed collection of similar data type items placed in contiguous memory locations that can be individually referenced by adding an index to a unique identifier. Index in this contest will be the location of the information within the array.
Let's give several examples of how to declare array. int ball[5];
Remember, arrays in c++ start at index 0, in the previous example you can access the index 0,1,2,3 and 4.
The elements field within square brackets [], representing the number of elements in the array, must be a constant expression, since arrays are blocks of static memory whose size must be determined at compile time, before the program runs. Arrays can be initialized in different ways: int ball[5]={0,1,2,3,4}; int ball[]={0,1,2,3,4,5}; int ball[] {0,1,2,3,4,5};
All previous initialization are correct. The compiler can figure out the number of elements within an array at compiling time. Moreover, the equal sing is not longer needed.
int ball[];
However, the previous will cause a compiling error. The compiler won't be able to figure out the data stored in the array (there is no data declared) nor the array size. This will produce an error saying "storage size of 'ball' isn't known. A good programming practice is always at least to provide the size of the array, so the compiler knows the amount of memory needed.
Multidimensional Arrays
Arrays in c++ can have as many dimensions you require, 2, 3, or more dimensions. This is how we declare multidimensional arrays.
int balls[2][2];
The previous array will have 2 rows and 2 columns, all of them initialized with the value 0.
int balls[2][2]={{1,2},{4,3}};
The previous array will have 2 rows and 2 columns, initialized with the previous values.
Reading and writing data
Two write data in any array is just as simple as the following statement:
int ball[2]=5; int balls[2][1]=5;
The first example will write 5 at the index or position 2 of the array ball. The second example will write the value 5 in row 3 and column 2 of the array balls.
Two write data in an array, the following statement is allowed: int x=ball[2]; int y=balls[2][1];
The previous statements will assign to x and y the values located at index "2" in ball and the row "2" and column "1" in balls respectively.
Passing array to a function
We can pass entire arrays to a function as an argument, the best way to explain this is with an small code. This code will consist of an array that with be passed to a function, this function will print the values of the array.
#include <string> #include <iostream> using namespace std; void print_array (int arg[], int length) { for (int n=0; n<length; ++n) cout << arg[n] << ' '; cout << '\n'; } int main () { int array[] = {5, 10, 15}; //array declaration print_array (array,3); //call to function print_array return 0; }
Let's mention the key aspects of the previous example code. array is passed to the function print_array that is declared as void, this mean that the function won't have any return value.
Array and pointers
Beginners are usually reluctant to use pointers. My personal advice, Use them, do not be afraid. The sooner you learn the concept, the better. Pointers are used for code optimization, since we can use the value of variable without copying the value of the variable itself. There are also the only way to allocate memory in C/C++. A more specific use of pointers will be covered in another post, for now, let's focused in how are arrays and pointers related.
An array work similar to a pointer to the first element. an array can be used to be implicitly converted to the pointer of the proper type. int array [5]; int *ptr_array; ptr_array=array;
After that, array and ptr_array will have similar properties, the main difference being that ptr_array can be assigned a different address. However, array can be assigned anything, and will always represent the same block of 5 elements of type int. While the ptr_array can be assigned to ptr_array, the following assignment will not have much meaning in C++, meaning that the assignment is not bidirectional.
array = ptr_array;
Also the operator [] can be the same when dealing with pointers, take a look at the next example.
array[5] = 1; // a [offset of 5] = 0 *(array+5) = 1; // pointed to by (a+5) = 0
The previous 2 expressions are equivalent. An array can be used as a pointer to its first element. Let's make another example.
#include <iostream> using namespace std; void display_array(int *ptr, int t) { for(int i=0;i<=t;i++) { cout<<*ptr+i<<endl; } } int main() { int lenght=2; int array[]={1,3,5}; display_array(array, lenght); return 0; } Output 1 2 3
As you can see, the previous example calls a function display_array, this function will take as an argument a pointer. As we can see, the pointer will take an address of the first value of the array. In terms of optimization, it might not have a difference with a function call by value. But in an array of thousands of values, it will make a huge difference, since every call by value will copy the data of array.
The previous program is equivalent to the following program. #include <iostream> using namespace std; void display_array(int ptr[], int t) { for(int i=0;i<=t;i++) { cout<<*ptr+i<<endl; } } int main() { int lenght=2; int array[]={1,3,5}; display_array(array, lenght); return 0; } Output 1 2 3
So, the 2 following function declarations are the same.
void display_array(int ptr[], int t) void display_array(int *ptr, int t)
This is only valid for arrays. But some programmers prefer to work with "[]" when working with arrays and functions. The programmer will know the function is expecting an array, on the compiler side, there will be no difference at all.
Enum Types
Data types allows to write programs in a more understandable way, it allows every possible value to be declared as a symbolic constant. Each enumerator is automatically assigned with an integer value depending of its position in the enumeration list, starting from 0 and increasing the number. The structure of the enumerated data types is following.
enum type { CONST_0, // assigned 0 CONST_1, // assigned 1 . . . CONST_n, // assigned n };
The enum class can be forced to start in a different integer value, if a different value is assigned. Let's see the following example
enum CARS\n{\n NISSAN=-2, // assigned -2\n CHEVROLET, // assigned -1 \n TESLA, // assigned 0 \n FORD, // assigned 1 \n KIA, // assigned 2 \n FIAT=6, \n BMW, // assigned 7 \n MERCEDEZ, // assigned 8 \n};\n Captain's log: week 2Structs
Let's go into the object oriented programming, and let's make it simple. What about if we need more than one variable to represent, let's say a car. This car has characteristics such as model, manufacturer, year, state, and some others.
std::string model; std::string state; int year;
Let's assume now that you have a data base of 3000 cars, you need to have control over each of the cars. Will you have to declare for each of the 3000 cars each of the variables just mentioned? The answer is no. We can create objects or structs (structure).
Declaring Structs
The usual form a struct is the following, there are some other variants, depending of the application.
struct type_name
{
member_type1 member_name1;
member_type2 member_name2;
member_type3 member_name3;
.
.
};
Another way that an struct can be declared is the following.:
struct type_name
{
member_type1 member_name1;
member_type2 member_name2;
member_type3 member_name3;
.
.
}object_names;
The difference lays that in the last one, the objects are declared with the struct. EIther way, both are valid in c++. Let's return to the car examples, and let's create a struct.
class car { std::string model; std::string state; int year; };
IMPORTANT: Do not forget the semi colon at the end.
Let's now use our example in a real program.
#include <iostream> #include <string> using namespace std; struct car { std::string model; std::string state; int year; }; // C++11 only car FORD={"Focus","Florida",2015}; car Tesla={"Models","California",2016}; car Chevrolet={"Camaro","Texas",2015}; int main() { cout<<"Display model information : "<<FORD.model<<endl; cout<<"Display model information : "<<Tesla.model<<endl; cout<<"Display model information : "<<Chevrolet.model<<endl; } Output Display model information : Focus Display model information : Models Display model information : Camaro
As we can see, this is pretty simple. Also, we have learned how to initialize the variables in very organized manner. Just keep in mind that the initialization done in the previous example is only available for c++11, make sure to compile with such capabilities.
In the similar way we accessed the information in our objects, we can assign them values. #include <iostream> #include <string> using namespace std; struct car { std::string model; std::string state; int year; }; // C++11 only car FORD={"Focus","Florida",2015}; car Tesla={"Models","California",2016}; car Chevrolet={"Camaro","Texas",2015}; int main() { FORD.year=2014; Tesla.state="Nevada"; Chevrolet.model="Blazer"; cout<<"Display year information : "<<FORD.year<<endl; cout<<"Display state information state : "<<Tesla.state<<endl; cout<<"Display model information model : "<<Chevrolet.model<<endl; } Display year information : 2014 Display state information state : Nevada Display model information model : Blazer
The values of the objects can be read or assigned using the structure object.member_name.
Nesting structs
While the following example could be valid, there might be better ways to represent it. But for sake of giving an example, we can consider the creation of another structure called driver. As you can see, we have declared right after the object. However, the programmer can add more objects if needed.
#include <iostream> #include <string> using namespace std; struct Car { std::string model; std::string state; int year; }; struct Driver { std::string last_name; std::string state; std::string job; int age; Car Nissan; }David; // C++11 only Car FORD={"Focus","Florida",2015}; Car Tesla={"Models","California",2016}; Car Chevrolet={"Camaro","Texas",2015}; int main() { David.last_name="Meyer"; David.job="Programmer"; David.age=28; David.Nissan.model="Altima"; David.Nissan.state="Georgia"; FORD.year=2014; Tesla.state="Nevada"; Chevrolet.model="Blazer"; cout<<"Display Last name information : "<<David.last_name<<endl; cout<<"Display Model information : "<<David.Nissan.model<<endl; cout<<"Display State information : "<<David.Nissan.state<<endl; }
We can see the structure call can be done following the hierarchy of the outermost structure that contains the nested structure. We can see that the two objects here are David and Nissan, the call it is done by David.Nissan to the object member of Nissan state. Take a look that Driver also has an object member state. To access to it we could do something like David.state. The call has to be done in a sequential manner up to reach the desired object member, Object_n,object_n-1,object_n-2.object.object_member.
Captain's log: week 3Object Oriented Programming
Object Oriented programming (OOP) was designed with the idea in mind of give to reduce the amount of code needed, and give an structure to the code easier to understand. Also to be able to reuse code in different applications. The Object oriented programming speaks for itself, we are going to program objects, and by objects, we can think about real life objects, that has properties and behave in different manners. Think about you are doing a database of the people that works in a middle-size company (around 50 employees). Each of those employees has different properties such as name, last name, age, position within the company, even people with the same position might do different things (we might consider this a different behavior). If we wouldn't have the OOP approach, can you imagine how many variables we should declare for each person within the company? A lot!.
Structs and classes are considered similar. However, programmers prefer to use classes when functions are declared within the class. Every object that surround us has many features or properties and behaviors. While we can't conceive an object without features, we can't conceive and object without its behavior. Meaning that there is a relationship with properties and behavior that we can't separate. Are we going to cover those strange concepts of OOP such as inheritance, encapsulation, abstraction, and polymorphism?. The answer is yes! We will. Be patient my young padawan, We will get there. Classes
Here we go, let's start with the very first thing you should know about OPP. Wait! You might have seen something similar before. Structs! Structures are pretty much classes that differ in the data flexibility.
struct Car { std::string model; std::string state; int year; }; class Car { public: std::string model; std::string state; int year; };
The two previous code snippets will get the same results. Also classes can be initialized in the same manner as structures.
You might be wondering why we have structs and classes. Moreover. What is that word within the class declaration that makes a reference to "public:". Let's discuss it. This is going to be the biggest difference (and probably the only one I have seen so far) among classes and structs. The access to the members of a class can be controlled while the access of the members of a structure are public by default. They are 3 different types of access within a class.
By default, object members are declared private, unless it is specified. For example, the following class has all its member private. Since public wasn't added. class Car { std::string model; std::string state; int year; void print_info() { cout<<"The year of "<<model<<" is "<< year<<" from "<< state<<endl; } };
A good programming practice is to declare the objects members private and the member functions public. Also, preceding members with the letter m will mean that is member of class. There are several rules out there to declare members. Something like this.
#include <iostream> #include <string> class Car { std::string m_model; std::string m_state; int m_year; public: void setCar(std::string model, std::string state, int year) { m_model = model; m_state = state; m_year = year; } void print_info() { std::cout<<"The year of "<<m_model<<" is "<< m_year<<" from "<< m_state<<std::endl; } }; int main() { Car car; car.setCar("Chevrolet","Florida",2014); car.print_info(); }
The year of Chevrolet is 2014 from Florida
Although, we don't have direct access to the variables, we can set them using the function setCar, and the information can be accessed using print_info. The different calling methods to functions can be implemented with classes and structures too. We will see that in a little bit.
Classes initialization
Constructors
A constructor is the proper way to initialize classes when the class is instantiated (declared). Constructors can be initialized with the default user-provided values. It is mandatory for a constructor to have the same name as the class. Also, constructors do not have return type.
#include <iostream> #include <string> class Car { std::string m_model; std::string m_state; int m_year; public: Car(std::string model, std::string state, int year) { m_model = model; m_state = state; m_year = year; } void print_info() { std::cout<<"The year of "<<m_model<<" is "<< m_year<<" from "<< m_state<<std::endl; } }; int main() { Car car("Chevrolet","Florida",2014); car.print_info(); }
In the previous code, we can see that the initialization of car takes places in the following code snippet.
Car(std::string model, std::string state, int year) { m_model = model; m_state = state; m_year = year; }
A more elegant and efficient way to initialize classes is using a member initialization list. The initialization list has the form a OOP code.
The following code shows the proper way of using the member initialization list. #include <iostream> #include <string> class Car { std::string m_model; std::string m_state; int m_year; public: Car(std::string model, std::string state, int year): m_model(model), m_state(state), m_year(year) { } void print_info() { std::cout<<"The year of "<<m_model<<" is "<< m_year<<" from "<< m_state<<std::endl; } }; int main() { Car car("Chevrolet","Florida",2014); car.print_info(); }
Let's take a closer look to the class initialization using member list. We can see now that there is no assignment needed withing the brackets. This type of initialization allows to pass arguments by value, or even by reference. Also, allows the uniform initialization or the member initialization list.
Car(const std::string &model,const std::string &state,const int &year)
The previous initialization is different to the following initialization, can you spot the difference?. Take a closer look, the variables were initialized using uniform initialization.
Car(std::string model, std::string state, int year): m_model{model}, m_state{state}, m_year{year} { }
0 Comments
Leave a Reply. |
About meEvery venture in an unknown territory is exciting to me. I ended up working with autonomous robots using knowledge from fields such as; computer vision, Bayesian estimation, control theory, neural networks, and SLAM. I have always been fascinated by aerial and ground mobile vehicles. Thankfully I had the chance to work on algorithms that bring them to life. Archives |