06 CPP11

You might also like

Download as pptx, pdf, or txt
Download as pptx, pdf, or txt
You are on page 1of 37

Korszerű programozási technikák

C++11
A C++11
• A C++ nyelv szabványa 2011-ben jelent meg

• A nyelv sokat fejlődött azóta, legutolsó szabvány a C++20


STL tárolókhoz
köthető újítások
Az auto kulcsszó
• Az auto kulcsszó egy változótípust jelöl

• Automatikusan felveszi a jobb oldalon levő változó típusát

• Fordítási időben a függvény visszatérése alapján


Az auto kulcsszó
STL tároló bejárása eddigi tudással STL tároló új bejárása

map<int, int> mapecske; map<int, int> mapecske;


{…} //feltöltés {…} //feltöltés
map<int, int>::iterator it = mapecske.begin(); auto it = mapecske.begin();
while(it != mapecske.end()) { while(it != mapecske.end()) {
cout << it->first << ” ” << it->second cout << it->first << ” ” <<
<< endl; it->second << endl;
it++; it++;
} }
Range-based loops
• A „foreach” ciklus

• Számtalan programozási nyelvben létezik

• Fő szerepe, hogy egy tárolót bejárhatunk nagyon rövid szintaktika


használatával

• Saját tárolóra is működik, ha rendelkezik belső iterator osztállyal,


amelyben van ++, != és indirekciós (*) operátor túlterhelés, továbbá
a tárolónak van begin()és end()metódusa
Range-based loops
vector<vector<int>> matrix; //C++11-ben nem kell szóköz a >> közé
Range-based loops
vector<vector<int>> matrix; //C++11-ben nem kell szóköz a >> közé

// Egyszerű bejárás
for(auto it : matrix) { //A matrix elemeinek a másolatával dolgozik
for(auto jt : it) {
cout << jt << ” ”;
}
cout << endl;
}
Range-based loops
vector<vector<int>> matrix; //C++11-ben nem kell szóköz a >> közé

// Feltöltés
for(auto & it : matrix) { //Referenciaként kell átvenni módosításhoz
for(auto & jt : it) {
jt = 1;
}
}
Iterátortípusok
• const_iterator esetén használjunk begin() és end() helyett
cbegin() és cend() függvényeket

• reverse_iterator esetén használjunk rbegin() és rend()


metódusokat
Decltype
• Változó vagy visszatérési érték típusának lekérdezése

• Változó deklarálásához használjuk

• Leggyakrabban sablon és összetett tárolók esetén


Decltype
string str;
decltype(str) str2;

map<vector<int>, list<vector<int>>> foo;


decltype(foo.begin()) it;

template<class T, class U>


auto add(T t, U u) -> decltype(t + u)
{
return t + u;
}
nullptr
• C++ban a NULL int típusú

• Gondoljuk meg az alábbi esetet


void foo(int) {…}
void foo(char*) {…}
{…}

foo(NULL);
nullptr
• C++11-ben bevezették a nullptr kulcsszót

• Implicit kasztolható más típusú pointerre és boolra

• Saját típusa van


• decltype(std::nullptr) vagy
• std::nullptr_t
template< class T > struct is_pointer
• Eldönti, hogy T egy pointer-e egy objektumra vagy függvényre

• #include <type_traits>
template< class T > struct is_pointer
#include <iostream>
#include <type_traits>

class A {};

int main() {
std::cout << std::boolalpha; //0 és 1 helyett true és false
std::cout << std::is_pointer<A>::value << '\n';
std::cout << std::is_pointer<A *>::value << '\n';
std::cout << std::is_pointer<A &>::value << '\n';
std::cout << std::is_pointer<int>::value << '\n';
std::cout << std::is_pointer<int *>::value << '\n';
std::cout << std::is_pointer<int **>::value << '\n';
std::cout << std::is_pointer<int[10]>::value << '\n';
std::cout << std::is_pointer<std::nullptr_t>::value << '\n';
}
template< class T > struct is_pointer
#include <iostream>
#include <type_traits>

class A {};

int main() {
std::cout << std::boolalpha; //0 és 1 helyett true és false
std::cout << std::is_pointer<A>::value << '\n'; //false
std::cout << std::is_pointer<A *>::value << '\n';
std::cout << std::is_pointer<A &>::value << '\n';
std::cout << std::is_pointer<int>::value << '\n';
std::cout << std::is_pointer<int *>::value << '\n';
std::cout << std::is_pointer<int **>::value << '\n';
std::cout << std::is_pointer<int[10]>::value << '\n';
std::cout << std::is_pointer<std::nullptr_t>::value << '\n';
}
template< class T > struct is_pointer
#include <iostream>
#include <type_traits>

class A {};

int main() {
std::cout << std::boolalpha; //0 és 1 helyett true és false
std::cout << std::is_pointer<A>::value << '\n'; //false
std::cout << std::is_pointer<A *>::value << '\n'; //true
std::cout << std::is_pointer<A &>::value << '\n';
std::cout << std::is_pointer<int>::value << '\n';
std::cout << std::is_pointer<int *>::value << '\n';
std::cout << std::is_pointer<int **>::value << '\n';
std::cout << std::is_pointer<int[10]>::value << '\n';
std::cout << std::is_pointer<std::nullptr_t>::value << '\n';
}
template< class T > struct is_pointer
#include <iostream>
#include <type_traits>

class A {};

int main() {
std::cout << std::boolalpha; //0 és 1 helyett true és false
std::cout << std::is_pointer<A>::value << '\n'; //false
std::cout << std::is_pointer<A *>::value << '\n'; //true
std::cout << std::is_pointer<A &>::value << '\n'; //false
std::cout << std::is_pointer<int>::value << '\n';
std::cout << std::is_pointer<int *>::value << '\n';
std::cout << std::is_pointer<int **>::value << '\n';
std::cout << std::is_pointer<int[10]>::value << '\n';
std::cout << std::is_pointer<std::nullptr_t>::value << '\n';
}
template< class T > struct is_pointer
#include <iostream>
#include <type_traits>

class A {};

int main() {
std::cout << std::boolalpha; //0 és 1 helyett true és false
std::cout << std::is_pointer<A>::value << '\n'; //false
std::cout << std::is_pointer<A *>::value << '\n'; //true
std::cout << std::is_pointer<A &>::value << '\n'; //false
std::cout << std::is_pointer<int>::value << '\n'; //false
std::cout << std::is_pointer<int *>::value << '\n';
std::cout << std::is_pointer<int **>::value << '\n';
std::cout << std::is_pointer<int[10]>::value << '\n';
std::cout << std::is_pointer<std::nullptr_t>::value << '\n';
}
template< class T > struct is_pointer
#include <iostream>
#include <type_traits>

class A {};

int main() {
std::cout << std::boolalpha; //0 és 1 helyett true és false
std::cout << std::is_pointer<A>::value << '\n'; //false
std::cout << std::is_pointer<A *>::value << '\n'; //true
std::cout << std::is_pointer<A &>::value << '\n'; //false
std::cout << std::is_pointer<int>::value << '\n'; //false
std::cout << std::is_pointer<int *>::value << '\n'; //true
std::cout << std::is_pointer<int **>::value << '\n';
std::cout << std::is_pointer<int[10]>::value << '\n';
std::cout << std::is_pointer<std::nullptr_t>::value << '\n';
}
template< class T > struct is_pointer
#include <iostream>
#include <type_traits>

class A {};

int main() {
std::cout << std::boolalpha; //0 és 1 helyett true és false
std::cout << std::is_pointer<A>::value << '\n'; //false
std::cout << std::is_pointer<A *>::value << '\n'; //true
std::cout << std::is_pointer<A &>::value << '\n'; //false
std::cout << std::is_pointer<int>::value << '\n'; //false
std::cout << std::is_pointer<int *>::value << '\n'; //true
std::cout << std::is_pointer<int **>::value << '\n'; //true
std::cout << std::is_pointer<int[10]>::value << '\n';
std::cout << std::is_pointer<std::nullptr_t>::value << '\n';
}
template< class T > struct is_pointer
#include <iostream>
#include <type_traits>

class A {};

int main() {
std::cout << std::boolalpha; //0 és 1 helyett true és false
std::cout << std::is_pointer<A>::value << '\n'; //false
std::cout << std::is_pointer<A *>::value << '\n'; //true
std::cout << std::is_pointer<A &>::value << '\n'; //false
std::cout << std::is_pointer<int>::value << '\n'; //false
std::cout << std::is_pointer<int *>::value << '\n'; //true
std::cout << std::is_pointer<int **>::value << '\n'; //true
std::cout << std::is_pointer<int[10]>::value << '\n'; //false
std::cout << std::is_pointer<std::nullptr_t>::value << '\n';
}
template< class T > struct is_pointer
#include <iostream>
#include <type_traits>

class A {};

int main() {
std::cout << std::boolalpha; //0 és 1 helyett true és false
std::cout << std::is_pointer<A>::value << '\n'; //false
std::cout << std::is_pointer<A *>::value << '\n'; //true
std::cout << std::is_pointer<A &>::value << '\n'; //false
std::cout << std::is_pointer<int>::value << '\n'; //false
std::cout << std::is_pointer<int *>::value << '\n'; //true
std::cout << std::is_pointer<int **>::value << '\n'; //true
std::cout << std::is_pointer<int[10]>::value << '\n'; //false
std::cout << std::is_pointer<std::nullptr_t>::value << '\n'; //false
}
Osztályon belüli változások
• Adattagnak értéket adhatunk deklarációnál is

class foo {

private:
int a = 125;
float c = 65.4;
};

• Ha a konstruktorban valamelyiknek nem adunk értéket, ezt veszi fel


Osztályon belüli változások
• Bizonyos függvények meghívását letilthatjuk (osztályon belül is)

class Foo{
Foo(const Foo& other) = delete;
Foo& operator=(const Foo& other) = delete;
void bar() = delete;
void bar(int);
};

• Csak int típussal hívató meg a bar függvény


Osztályon belüli változások
• Meg lehet tiltani osztályokból való származtatást vagy csak bizonyos
függvények túlterhelését
class BaseClass final {
public:
BaseClass(int value);
};

class DerivedClass : public BaseClass {


};
// cannot derive from ‘final’ base ‘BaseClass’ in
derived type ‘DerivedClass’
Osztályon belüli változások
• Meg lehet tiltani osztályokból való származtatást vagy csak bizonyos
függvények túlterhelését
class BaseClass {
public:
virtual void print(int i) final;
};

class DerivedClass : public BaseClass {


public:
virtual void print(int i);
};
// virtual function ‘virtual void DerivedClass::print(int)’
// overriding final function ‘virtual void BaseClass::print(int)’
Osztályon belüli változások
• Ha származtatunk egy ősosztályból, aminek sok konstruktora van,
amiket a gyerekosztályban is használni szeretnénk, akkor mindet
egyenként létre kell hozni
• C++11-ben van lehetőség ezt elkerülni
class BaseClass {
public:
BaseClass(int value);
};

class DerivedClass : public BaseClass {


public:
using BaseClass::BaseClass;
};
Osztályon belüli változások
• Ebben az esetben a gyerekosztályban létezni fog az ősosztály összes
konstruktora, megegyező működéssel

• Nem lehet szelektálni, vagy mindegyiket átveszi, vagy egyiket sem

• A gyerekosztályban ezután nem hozhatunk létre olyan konstruktort,


melynek szintaktikája szerepel az ősosztályban
Inicializáló lista
• Egy lista segítségével inicializálhatunk
vector<int> v = {0, 1, 2, 3, 4};

• C++11 megengedi, hogy konstruktorban egy ilyen inicializáló listát


adjunk meg
• Ehhez egy sablon is társul
std::initializer_list
#include <iostream>
#include <vector>
using namespace std;

class Foo {
vector<int> bar;
int a;
float b; Foo foo(5, 3.14f, {1, 2, 3, 4, 5});
public: foo.print();
Foo(int a, float b, initializer_list<int> l)
{
this->a = a;
this->b = b;
bar = l; for (int i : {1, 2, 3, 4, 5})
} {
void print() const { cout << i << endl;
cout << "a: " << a << endl; }
cout << "b: " << b << endl;
for( auto it : bar)
cout << it << " ";
cout << endl;
}
};
initializer_list<int> getPos() {
return {3, 16, 25, 5, 8};
}

string str = "example string";


for (int i : getPos()) {
cout << "character " << i << ": ";
if (i > str.length())
cout << "outside of string" << endl;
else
cout << str[i] << endl;
}
Gyakorló feladat
• Készítsünk egy MinMax osztályt, amely egyetlen konstruktorral
rendelkezik
• A konstruktor egy inicializáló listát vár paraméterül és a tartalmát nem menti
el, viszont kiszámolja és eltárolja a következő adatokat: legkisebb és
legnagyobb elem
• Az eltárolt adatokat lehessen lekérni az osztálytól
• Írjuk meg a kisebb operátort is
• Két MinMax objektum közül az a kisebb, ahol a minimum értéke kisebb
Gyakorló feladat
• Származtassunk az osztályból egy MinMaxAvg gyerekosztályt, amely
az átlagot is kiszámolja és elmenti

• Gondoskodjunk róla, hogy a gyerekosztályt semmilyen módon ne


lehessen lemásolni (másoló konstruktor, = operátor), valamint belőle
származtatni sem
Gyakorló feladat
• Származtassunk egy OrderedVector osztályt a vector-ból, ami
csak az alapértelmezett konstruktorral rendelkezik

• Definiáljuk felül a push_back metódust úgy, hogy az elemeket


növekvő sorrendben adja hozzá a tárolóhoz
Gyakorló feladat
• Származtassunk egy SmartVector osztályt a vector-ból, ami
meghívható minden olyan konstruktorral, amivel a vector
• Az osztály működése általános esetben ne térjen el a vector-étól
• Amennyiben viszont az osztályban mutatókat tárolunk a működés
módosuljon
• A push_back függvény csak akkor adja hozzá az adatot, ha az nem
nullptr
• A destruktor szabadítsa fel az elemeket egyesével

You might also like