C++

Home  /  Programming  /  C++

C++


Основы

    // явное преобразование типов
    float x = 5.6f;
    cout << (int)x << endl;

    // остаток от деления
    cout << 6 % 8 << endl;

    // в цикле может быть много условий и инкрементирующих выражений, разделенных запятой
    // условие должно быть одно
    for (int j = 0, i = 100; j < 50; j++, --i) { break; }

    int n = 1;
    while(n != 0) { break; }

    do { break; } while (n != 0);

    // если правда, min = i, иначе min = j
    int i = 1, j = 2, min = (i < j) ? i : j;

    // структура хранит данные, класс - данные и функции
    // их можно вкладывать друг в друга
    struct MyStruct { int a; float c; };

    // доступ к элементам структуры
    MyStruct ms;
    ms.a = 5;
    ms = { 1, 2 };

    enum MyEnum { One = 3, Two, Three };
// "аргументы по умолчанию" указываются в конце
// & - передача адреса переменной для изменения ее самой, а не ее копии
void MyFunc(int& x, float b = 0.5f) { x = 5; };
// рекурсия для вычисления факториала
unsigned long factFunc(unsigned long n)
{
    if (n > 1)
        return n * factFunc(n - 1);
    else
        return 1;
}
// встраиваемая ф-я, которая должна содержать 1-2 оператора
inline void MyFunc() { }

// возвращение значения по ссылке позволяет не копировать большие объемы данных и
// дает возможность вызывать ф-ю в качестве левого операнда операции присваивания
int x;
int& SetX() { return x; }

int main()
{
    SetX() = 5;
    std::cout << x << std::endl;
    return 0;
}
// константные аргументы нельзя изменить
void MyFunc(int& a, const int& b)
{
    a = 5; // правильно
    //b = 7; // ошибка
}

Классы

// члены класса по умолчания скрыты, структуры - открыты
class A
{
public:
    A() : xCo(0), yCo(0) {} // конструктор по умолчанию
    // список инициализации конструктора
    A(int x, int y) : xCo(x), yCo(y) { /* тело конструктора */ }

    int xCo;
    int yCo;

    // константный метод не позволяет менять поля своего класса
    // модификатор const указывают при объявлении и определнии ф-ии
    void MyFunc() const
    {
        //yCo = 0; // ошибка
    }
};

int main()
{
    A objA(5, 7);
    A objB;
    A objC = objA; // конструктор копирования

    // константный объект может вызывать лишь константные методы
    const A objD;

    return 0;
}

Массивы

// передача массива в ф-ю
const int i = 2, j = 2;
void MyFunc(int arr[i][j])
{
    for (int iarr = 0; iarr < i; iarr++)
        for (int jarr = 0; jarr < j; jarr++)
            cout << arr[iarr][jarr];
}

// массив структур
struct MyStruct { int a; int b; };

int main()
{
    const int size = 5;
    int arr1[size];
    for(int i = 0; i < size; i++) {}
    
    int arr2[] = { 1, 2, 3, 4, 5 };

    // 5й элемент будет установлен в 0
    int arr3[5] = { 1, 2, 3, 4 };

    // передача массива в ф-ю
    int arr4[2][2] = { { 1, 2 }, { 3, 4 } };
    MyFunc(arr4);

    // массив структур
    MyStruct structArr[5];
    structArr[0].a = 5;

    // строковые переменные
    const int MAX = 80;
    char str1[MAX];
    cin >> str1;
    cout << str1;
    char str2[] = "ABCD";

    return 0;
}

Наследование

// если один и тот-же метод существует в базовом и производном классе,
// то будет вызван метод произвожного класса

// для абстрактного класса нельзя создать экземпляры, от него можно
// только наследоваться
class A
{
private:    int a;
protected:  int b;
public:     int c;
};

class B : public A // public
{
public:
    void MyFunc()
    {
        a = 0; // ошибка
        b = 0;
        c = 0;
    }
};

class C : private A // private
{
    void MyFunc()
    {
        a = 0; // ошибка
        b = 0;
        c = 0;
    }
};

int main()
{
    B objB;
    objB.a = 0; // ошибка
    objB.b = 0; // ошибка
    objB.c = 0;

    C objC;
    objC.a = 0; // ошибка
    objC.b = 0; // ошибка
    objC.c = 0; // ошибка
    return 0;
}
// множественное наследование
class A {};
class B {};
class C : public A, public B {};

Указатели

Ссылка & возвращает адрес, указатель * возвращает значение

    int a = 57;
    cout << &a << endl; // адрес

    int* b;             // указатель на int
                        // 'int* b' идентично 'int *b' 
                        // int *a, *b, *c;
    cout << &b << endl; // адрес

    b = &a;             // присвоим 'b' значение адреса 'a'
    cout << b << endl;  // адрес
    cout << *b << endl; // значение '57' - разыменование
    int a, b;
    int* c;
    c = &a;
    *c = 5; // то же самое, что a = 5
    b = *c; // то же самое, что b = c
    cout << a << b << *c << endl; // 555

    // адрес, который помещается в указатель, должен быть одного с ним типа
    int d;
    float e = &d; // ошибка

    //.. но есть указатель, который может указывать на любой тип данных
    // используются для передачи в ф-ии, работающие с разными типами данных
    int intVar;
    float floatVar;
    
    int* ptrInt;
    float* ptrFloat;
    void* ptrVoid;

    ptrInt = &intVar;
    ptrInt = &floatVar; // ошибка
    ptrVoid = &intVar;
    ptrVoid = &floatVar;

    // доступ к элементу массива через указатель
    int arr[5] = { 1, 2, 3, 4, 5 };
    for (int i = 0; i < 5; i++)
        cout << *(arr + i); // выражение *(arr + i) эквивалентно arr[i]
// передача аргумента по ссылке
void MyFunc(int& b) { b = 7; }

int main()
{
    int a = 5;
    MyFunc(a);
    cout << a; // 7
    return 0;
}
// передача аргумента по указателю
void MyFunc(int* b) { *b = 7; }

int main()
{
    int a = 5;
    MyFunc(&a);
    cout << a; // 7
    return 0;
}
// передача массива по указателю
void MyFunc(int* arr)
{
    for (int i = 0; i < 5; i++)
        *arr++ *= 2; // инкремент индекса массива и изменение значения
}

int main()
{
    int arr[5] = { 1, 2, 3, 4, 5 };
    MyFunc(arr);
    for (int i = 0; i < 5; i++)
        cout << arr[i] << endl;
    return 0;
}
    // new delete
    // обычно new вызывают в конструкторе, а delete - в деструкторе
    int* a = new int;
    delete a;

    char* b = new char[5];
    delete[] b;
// операция '->'
class A
{
public:
    void MyFunc() {}
};

int main()
{
    A* objA = new A;
    // ссылка на метод класса из объекта, на который указывает objA
    objA->MyFunc();
    (*objA).MyFunc(); // то же самое

    // операция '->' работает с указателями на объекты так же,
    // как операция '.' работает с объектами
    return 0;
}

Виртуальные функции

class A
{
public:
    void MyFunc() { cout << "A" << endl; }
};

class B : public A
{
public:
    void MyFunc() { cout << "B" << endl; }
};

class C : public A
{
public:
    void MyFunc() { cout << "C" << endl; }
};

int main()
{
    // Компилятор не смотрит на содержимое указателя ptr, а
    // выбирает тот метод, который удовлетворяет типу указателя
    A* ptr;
    B objB;
    C objC;

    ptr = &objB;
    ptr->MyFunc(); // выведет 'A'
    
    ptr = &objC;
    ptr->MyFunc(); // выведет 'A'
    
    return 0;
}
class A
{
public:
    // добавляем слово virtual
    virtual void MyFunc() { cout << "A" << endl; }
};

class B : public A
{
public:
    void MyFunc() { cout << "B" << endl; }
};

class C : public A
{
public:
    void MyFunc() { cout << "C" << endl; }
};

int main()
{
    A* ptr;
    B objB;
    C objC;

    ptr = &objB;
    ptr->MyFunc(); // выведет 'B'
    
    ptr = &objC;
    ptr->MyFunc(); // выведет 'C'
    
    return 0;
}
class A
{
public:
    // если класс содержит чистую виртуальную функцию,
    // то он абстрактный, его экземпляр создать нельзя
    virtual void MyFunc() = 0;
};

int main()
{
    A objA; // ошибка
    return 0;
}

Шаблонные функции

// шаблонная ф-я позволяет использовать одну запись для
// работы с разными типами данных
// шаблонными могут быть тип возвращаемого значения и аргументы
template<class T>
void MyFunc(T var) {}

int main()
{
    int a = 5;
    float b = 5.7;
    MyFunc(a);
    MyFunc(b);

    return 0;
}
template<class T, class Z>
void MyFunc(T var1, Z var2, int var3 = 2) {}

int main()
{
    int a = 5;
    float b = 5.7;

    // шаблонные типы должны быть определены, а нешаблонные могут
    // использовать аргументы по умолчанию
    MyFunc(a, 2);
    MyFunc(b, a);
    MyFunc(1, 2, 3);

    return 0;
}
// количество экземпляров шаблонной ф-и в памяти
// резко растет с увеличением числа аргументов

// макросы редко изпользуют, т.к. они не осуществляют проверку типов
Comments are closed.