A group of subject designed to learn CPP through differents exercices, here are some explanation about the specification of every modules.
- CPP00: Strings and I/O Manipulation
- CPP01: New, class, ...: basics
- CPP02: Operator overload
- CPP03: Inheritance : basics
- CPP04: Polymorphism
- CPP05: Exception, Try, Catch
- CPP06: cast, convert...
- CPP07: Template
- CPP08: Containers
To write some text on STDOUT we use the '<<' operator to push a string into it.
std::cout << "Hello World!" << std::endl;
In C++
we have the class string
, this class is defined in <string>
.
#include <string>
#include <iostream>
int main()
{
std::string name;
std::getline(std::cin, name);
std::cout << "My name is: " << name << std::endl;
}
We can use std::cin
to communicate through STDIN and write information to our code for example above with the function getline
Sometimes we want to use an object outside of the function that created it:
Cat createCat(void)
{
Cat albert;
return (albert);
}
int main()
{
Cat albert = createCat();
}
For example we can't do something like that because albert is destroyed when the function createCat() end, so we have to use the keyword new
to create our Cat on the heap and not on the stack
Cat *createCat(void)
{
Cat *albert = new Cat();
return (albert);
}
int main()
{
Cat *albert = createCat();
delete albert;
}
Never forget that you have to destroy every object instanciated with the keyword new
by using delete
Cat *createCat(void)
{
Cat *groupsOfCats = new Cat[10];
return (groupsOfCats);
}
int main()
{
Cat *groupsOfCats = createCat();
delete []groupsOfCats;
}
Use delete[]
to destroy entire array of object without having to iterate through it
in C++
you can overload all the operator, for example i want a new class MyInt, it have one attribute int
number and i want to change the comportement of the +
operator
class MyInt
{
private:
int number;
public:
MyInt operator+(const &rhs)
{
return (this->number - rhs.number);
}
};
int main()
{
MyInt int1(43);
MyInt int2(1);
std::cout << int1 + int2 << std::endl
// output: 42
}
now the +
operator acts like the -
operator. You can define in your class all the operator (>
, <
, <=
, >=
, !=
, ==
, >>
, <<
, =
, []
, *
, ...)
A class can inherit from another and share the same function and the same attributes
class Animals
{
protected:
int numOfLegs;
public:
void getNumOfLegs() const;
void walk();
};
class Cat : public Animals
{
public:
void meow();
}
int main()
{
Cat felix();
Animals thing();
felix.walk(); //Works!
felix.getNumOfLegs(); //Works!
thing.meow(); //Don't works!
}
if a base class have a virtual function, this function can be overriden in the derived class
class Animals
{
protected:
int numOfLegs;
public:
void getNumOfLegs() const;
virtual void walk() {
std::cout << "i'm walking!" << std::endl;
};
};
class Cat : public Animals
{
public:
virtual void walk() {
std::cout << "i'm meowing" << std::endl;
};
};
int main()
{
Cat felix();
Animals thing();
felix.walk(); //"i'm meowing!"
felix.getNumOfLegs(); //Works!
thing.walk(); //"i'm walking"
}
if a class have a virtual methods equals to zero, this class is an interface, it can't be instanciated, it's just useful for inheritance
class Animals
{
protected:
int numOfLegs;
public:
void getNumOfLegs() const;
virtual void walk() = 0;
};
class Cat : public Animals
{
public:
virtual void walk()
{
std::cout << "i'm meowing" << std::endl;
};
};
int main()
{
Cat felix();
Animals thing(); //DON'T WORK
}
Sometimes it's necessary to have the destructor in virtual if you delete an instance from a derived class through a pointer of a base class
class Base
{
// some virtual methods
};
class Derived : public Base
{
~Derived()
{
// Do some important cleanup
}
};
int main()
{
Base *b = new Derived();
// use b
delete b; // Here's the problem! (undefined behavior)
}
Since Base's destructor is not virtual and b is a Base* pointing to a Derived object, delete b has undefined behaviour
The try
and catch
keyword are very useful to spot and display error messages, here a little piece of code to explain the methods.
Nested class are an important part in creating exception, you define a nested class inheriting std::exception
in order to throw error in your code.
class Test {
public:
//here is a nested class
class ProblemsHere : public std::exception {
public:
virtual const char *what() const throw {
return ("the custom message u want");
}
}
void doThing(std::string things);
}
void Test::doThing(std::string things) {
if (!things)
throw ProblemsHere(); //throw an error, the name of the nested class
//with parenthesis
else
return (things);
}
int main() {
Test obj;
try {
obj.doThing();
} catch (std::exception &e) {
std::cout << e.what() << std::endl;
}
//the execution continue here
}
with the keyword try we execute an instruction, if the instruction fail, we catch an std::exception &e and use the function what to display the custome message we want.
The executions of your code continue after the try and catch block.