Открытый канал ID 77000965607995

Я просто спросить про указатели C++ (изучаю С++).

Начинаю свой путь изучения С++. Пока читаю книгу Прата С++ 6 издание.
Здесь нет каких-то рекомендаций, канал создан, чтобы автор не забыл, что он изучал..

Публикации за период

По реакциям

Поиск и вся лента — после бесплатной регистрации. Свои даты — по подписке; владелец канала видит их бесплатно. Сортировка по реакциям — по подписке. Зарегистрироваться

Загрузка…

В дополнение:
Это происходит, потому что в АБК Role() виртуальный и в производных классах остаётся виртуальным. А при вызове Show() сначала определяется для кого Show() вызывать (ученика, учителя и тд), а после в самом методе вызывается Role() и точно также идет определение "к кому принадлежит Role()".

Также в main создадим указатель school из 5 объектов, указатель типа Person, благодаря этому мы можем спокойной создавать массив из производных классов от АБК и использовать их.

Начиная с класса VicePrincipal, в метод Show() был добавлен тернарный оператор, который добавляет окончание к слову class при необходимости:

void Show() const {
Teacher::Show();
std::cout << "Managed " << m_classesManaged;
m_classesManaged > 1 ? std::cout << " classes" : std::cout << " class";
std::cout << std::endl;
}

Просмотры: 25
Перейти в пост Открыть в MAX Сообщить о неточности
Загружаем изображение…
Глава 13. Наследование классов
Сделаем класс Person абстрактным базовым классом (АБК), так как в контексте школы не может быть просто человека. Абстрактный класс задаёт общие черты, а специфику мы делаем в производных классах. Для создания АБК нам необходимо "занулить" виртуальную функцию, стоит помнить, что объекты нельзя создавать.

Код:

//заголовочный файл person.h
#pragma once
#include <string>

class Person {
protected:
std::string m_name;
int m_age;
public:
Person() : m_name("Noname"), m_age(0) {}
Person(std::string name, int age) : m_name(name), m_age(age) {}
virtual void Show() const = 0;
virtual std::string Role() const = 0;

};

class Student : public Person {
private:
int m_grade;
double m_averageScore;
public:
Student() : Person("Noname", 0), m_grade(0), m_averageScore(0.0) {}
Student(std::string name, int age, int grade, double averageScore)
: Person(name, age), m_grade(grade), m_averageScore(averageScore) {
}

void Show() const {
std::cout << "Name: " << m_name << std::endl
<< "Age: " << m_age << std::endl
<< "Grade: " << m_grade << std::endl
<< "Average score: " << m_averageScore << std::endl
<< "Role: " << Role() << std::endl;
}

std::string Role() const {
return "student";
}
};

class Teacher : public Person {
protected:
std::string m_subject;
double m_salary;
public:
Teacher(std::string n, int a, std::string s, double sal)
: Person(n, a), m_subject(s), m_salary(sal) {
}

void Show() const {
std::cout << "Name: " << m_name << std::endl
<< "Age: " << m_age << std::endl
<< "Subject: " << m_subject << std::endl
<< "Salary: " << m_salary << std::endl
<< "Role: " << Role() << std::endl;
}
std::string Role() const override { return "Teacher"; }
double Salary() const { return m_salary; }
};


class VicePrincipal : public Teacher {
int m_yearsOfExperience;
int m_classesManaged;
public:
VicePrincipal(std::string n, int a, std::string s, double sal, int y, int c)
: Teacher(n, a, s, sal), m_yearsOfExperience(y), m_classesManaged(c) {
}

void Show() const {
Teacher::Show();
std::cout << "Managed " << m_classesManaged;
m_classesManaged > 1 ? std::cout << " classes" : std::cout << " class";
std::cout << std::endl;
}
std::string Role() const { return "VicePrincipal"; }
};

class Principal : public VicePrincipal {
double m_schoolBudget;
public:
Principal(std::string n, int a, std::string s, double sal, int y, int c, double b)
: VicePrincipal(n, a, s, sal, y, c), m_schoolBudget(b) {
}

void Show() const {
VicePrincipal::Show();
std::cout << "Budget: " << m_schoolBudget << std::endl;
}
std::string Role() const override { return "Principal"; }
};

Код в main.cpp

//main.cpp
#include <iostream>
#include "person.h"

int main() {

Student Peter("Peter", 12, 5, 4.5);
Teacher t1("Izolda", 55, "History", 27500);
VicePrincipal vp1("Antonio", 77, "Math", 90000, 57, 1);
VicePrincipal vp2("Antonioresky", 78, "Math", 90100, 58, 2);
Principal p1("Oleg", 50, "informatics", 100000, 30, 5, 300000);

Person* school[5] = { &Peter, &t1, &vp1, &vp2, &p1 };

for (int i = 0; i < 5; ++i) {
school[i]->Show();
std::cout << std::endl;
}
return 0;
}

Консоль:
Name: Peter
Age: 12
Grade: 5
Average score: 4.5
Role: student

Name: Izolda
Age: 55
Subject: History
Salary: 27500
Role: Teacher

Name: Antonio
Age: 77
Subject: Math
Salary: 90000
Role: VicePrincipal
Managed 1 class

Name: Antonioresky
Age: 78
Subject: Math
Salary: 90100
Role: VicePrincipal
Managed 2 classes

Name: Oleg
Age: 50
Subject: informatics
Salary: 100000
Role: Principal
Managed 5 classes
Budget: 300000

Мы видим, что переопределенный метод Role() работает в каждом классе, даже, если мы подключаем часть Show() из наследуемого класса.
Просмотры: 20
Перейти в пост Открыть в MAX Сообщить о неточности
Загружаем изображение…
Глава 13. Наследование классов
Виртуальные функции.
Теперь рассмотрим такой случай, что у наших классов есть метод Show().

//заголовочный файл person.h
#pragma once
#include <string>
 
class Person {
protected:
    std::string m_name;
    int m_age;
public:
    Person() : m_name("Noname"), m_age(0) {}
    Person(std::string name, int age) : m_name(name), m_age(age) {}
    void Show() const { std::cout << m_name << ", " << m_age; }
};
 
class Student : public Person {
private:
    int m_grade;
public:
    Student() : Person("Noname", 0), m_grade(0) {}
    Student(std::string name, int age, int grade)
        : Person(name, age), m_grade(grade) {}
       
    void Show() const {
        Person::Show();
        std::cout << ", grade " << m_grade << std::endl;
    }
};

 
Сделаем указатель типа Person (базового класса) на производный класс Student и попытаемся вывести данные объекта. В заголовочном фале person.h в производном классе добавили метод Show(), где:
 Person::Show(); выводит данные от базового класса, а в производном, соответственно, добавили вывод grade (класс, в котором учится ученик).

//main.cpp
#include <iostream>
#include "person.h"
 
int main() {
 
    Person Ivan("Ivan", 12);
    Ivan.Show();
    std::cout << std::endl;
 
    Student Peter("Peter", 12, 5);
    Peter.Show();
   
    Person* pp = &Peter;
    pp->Show();
    return 0;
}

 
Вывод консоли:
Ivan, 12
Peter, 12, grade 5
Peter, 12

Как можем заметить, grade не был выведен указателем pp. Здесь показано статическое связывание, то есть тип указателя Person, в связи с чем была выведена часть данных метода класса Person, несмотря на то что указатель pp ссылается на объект класса Student.
Чтобы решить эту проблему добавим к методу Show класса Person virtual, то есть сделаем динамическое связывание.

virtual void Show() const { std::cout << m_name << ", " << m_age; }

Теперь в консоли получили такие данные:
Ivan, 12
Peter, 12, grade 5
Peter, 12, grade 5

Но нам следует добавить виртуальный деструктор, иначе может произойти утечка virtual ~Person(){}.
Просмотры: 17
Перейти в пост Открыть в MAX Сообщить о неточности
Загружаем изображение…
Глава 13. Наследование классов
Наследование необходимо, чтобы не писать множество классов, которые может объединять что-то общее. Наследование позволяет вынести общее в базовый класс, а специфику в производные.
В наследовании может быть множество отношений, в данной главе книги было представлено is-a (является). Возьмем школьную систему: ученик, учитель, завуч и директор (на рисунке представлено как будут наследоваться объекты).

//заголовочный файл person.h
#pragma once
#include <string>
 
class Person {
protected:
    std::string m_name;
    int m_age;
public:
    Person() : m_name("Noname"), m_age(0) {}
    Person(std::string name, int age) : m_name(name), m_age(age) {}
    void Show() const { std::cout << m_name << ", " << m_age << std::endl; }
};
 
class Student : public Person {
private:
    int m_grade;
public:
    Student() : Person("Noname", 0), m_grade(0) {}
    Student(std::string name, int age, int grade)
        : Person(name, age), m_grade(grade) {
    }
};

 

//main.cpp
#include <iostream>
#include "person.h"
 
int main() {
 
    Person Ivan("Ivan", 12);
    Ivan.Show
();
 
    Student Peter("Peter", 12, 5);
    Peter.Show
();;
 
}

Консоль:
Ivan, 12
Peter, 12 <- как можем заметить, не отображается класс ученика (grade)

Класс Student наследует класс Person открыто (public). Это значит, что у класса Student будут теже методы, что и в базовом классе.  
 
Также используются инициализаторы (могут использовать только в конструкторах), они позволяют инициализировать члены класса до того, как начнёт выполняться тело конструктора {}.
Есть разница в использовании инициализаторов и присваивания значений в теле конструктора.

// Вариант 1: список инициализаторов
Person(std::string name, int age) : m_name(name), m_age(age) {}
// Вариант 2: присваивание в теле
Person(std::string name, int age) {
    m_name = name;
    m_age = age;
};

Во втором варианте сначала name и age получают значения по умолчанию, а потом получают значения, в первом варианте – переменные получают значения, а после выполняется тело {}.

Некоторые правила:
1. Производный объект использует методы базового.
2. Указатель/ссылка базового на производный объект.

    Student Anna;
    Person* pt = &Anna;
    Person& ref = Anna;

3. Обратно (от производного на базовый) – нельзя без явного приведения (так как в производном у нас добавлены специфика, а в базовом нет таких полей связи с чем и возникает ошибка, при явном приведении это устраняется, но тоже нежелательно можем поймать мусор из памяти).

Student* ptr = (Student*)&Ivan;
Просмотры: 17
Перейти в пост Открыть в MAX Сообщить о неточности
Загружаем изображение…
Глава 12. Классы и динамическое выделение памяти
При почленном копировании копируется указатель, а не данные, что ведёт к двойному освобождению (конструктор Text() создаёт объект, деструктор ~Text() уничтожает объект). Показано на картинке.

#include <iostream>
#include <cstring>
 
class Text {
private:
    char * data;
    int length;
public:
    Text(const char * str) {
        length = std::strlen(str);
        data = new char[length + 1]; //динамическая память new
        std::strcpy(data, str);
    }
    ~Text() {
        delete[] data;
    }
};
 
int main() {
    Text t1("Hello");
    Text t2 = t1;
    return 0;
}

 
Здесь возникнет ошибка – двойное удаление, так как указатель data у объектов t1 и t2 указывает на одну и туже ячейку памяти, при завершении у одного объекта уже адрес у указателя удален, а у второго объекта указатель продолжает указывать на ту ячейку памяти, но адрес уже удален и повторное удаление невозможно, так как ячейка памяти уже очищена. В таких случаях используется глубокое копирование.

#include <iostream>
#include <cstring>
class Text {
private:
    char * data;
    int length;
public:
    //Конструктор по умолчанию
    Text(const char * str) {
        length = strlen(str);
        data = new char[length + 1];
        strcpy(data, str);
        std::cout << "Default constructor, data: " << &data << std::endl;
    }
    //Конструктор копирвания
    Text(const Text & other) {
        length = other.length;
        data = new char[length + 1];
        std::strcpy(data, other.data
);
        std::cout << "Copy constructor, data: "<< &data << std::endl;
    }
    // Оператор=
    Text & operator=(const Text & other) {
        if (this == &other) return *this;
        delete[] data; // сначала очищаем указатель
        length = other.length;
        data = new char[length + 1]; //добавляем новый адрес
        std::strcpy(data, other.data
);
        std::cout << "Operator=, this data: "<< &data << std::endl;
        std::cout << "Operator=, other data: "<< &other.data << std::endl;
        return *this;
    }
   
    ~Text() {
        delete[] data;
    }
};
 
int main() {
    Text t1("Hello");
    std::cout << "============" << std::endl;
    Text t2 = t1;
    std::cout << "============" << std::endl;
    Text t3("Hi");
    std::cout << "============" << std::endl;
    t3 = t1;
   
    return 0;
}

Консоль:
Default constructor, data: 0xffffd4a86330
============
Copy constructor, data: 0xffffd4a86320
============
Default constructor, data: 0xffffd4a86310
============
Operator=, this data: 0xffffd4a86310
Operator=, other data: 0xffffd4a86330

Здесь добавился конструктор копирования (в отличие от конструктора по умолчанию можем заметить что принимает тип Text, а не const char *), перегруженный оператор присваивания (как раз-таки, когда у нас при двух созданных объектах один приравнивается к другому).
Специальные функции-члены, генерируемые компилятором
1. Автоматически создаются, если не определены:
2. Конструктор по умолчанию
3. Конструктор копирования
4. Операция присваивания
5. Деструктор
6. Операция взятия адреса
Конструктор копирования по умолчанию — почленное копирование (поверхностное).
Операция присваивания по умолчанию — почленное присваивание.
Просмотры: 18
Перейти в пост Открыть в MAX Сообщить о неточности
Загружаем изображение…
Основное из 11 главы Прата.

Дружественные функции.
Это функции, не являющиеся членами класса, но имеющие доступ к закрытым данным. Нужны, когда левый операнд не является объектом класса. Для того, чтобы функция стала дружественной, необходимо добавить friend перед типом функции, пример:
friend std::ostream& operator<<(std::ostream & os, const Distance & d);
Здесь, кстати, мы используем перегрузку оператора <<, для того, чтобы выводить объекты необходимо возвращать сам объект cout (std::ostream), который мы обозначим как os.
Преобразование.
Не думаю, что это хороший способ, но посмотрим на него.
У нас будет конструктор с 1 аргументом и мы благодаря это сможем делать неявное преобразование:
file.h //заголовочный файл
Distance(int m);
main.cpp //основной файл исполнения


#include <iostream>
#include "file.h"
Distance::Distance(int m, int cm) : meters(m), centimeters(cm) {}
Distance::Distance(int m) {
    meters = m;
};
Distance Distance::operator+(const Distance& other) {
    centimeters = centimeters + other.centimeters;
    meters += other.meters + centimeters / 100;
    centimeters %= 100;
    return *this;
}
std::ostream & operator<<(std::ostream & os, const Distance& d) {
    os << "m: "<< d.meters << " cm: "  << d.centimeters << std::endl;
    return os;
}
void Distance::show() const {
    std::cout << meters << " m " << centimeters << " cm" << std::endl;
}
 
int main() {
    Distance d = 50;
    std::cout << d << std::endl;
    return 0;
}

 
Чем плохо такое преобразование, может возникнуть момент, когда мы случайно объект делаем числом или другим типом не ожидая этого, как показано в последней строке – так происходит из-за неявного преобразования. Чтобы исключить  возможные проблемы, в заголовочный файл file.h добавим к конструктору ключевое слово explicit, что запретит неявное преобразование.

    // Distance d = 50;  - ошибка, неявное преобразование
    Distance d(50); // явное преобразование, мы так и задумывали.
    std::cout << d << std::endl;
Просмотры: 17
Перейти в пост Открыть в MAX Сообщить о неточности
Основное из главы 11. Прата.

#include <iostream>
#include "file.h"
Distance::Distance(int m, int cm) : meters(m), centimeters(cm) {}
Distance Distance::operator+(const Distance& other) {
    centimeters = centimeters + other.centimeters;
    meters += other.meters + centimeters / 100;
    centimeters %= 100;
    return *this;
}
void Distance::show() const {
    std::cout << meters << " m " << centimeters << " cm" << std::endl;
}

int main() {
    Distance a, b(5, 40), c(5, 60);
    std::cout << "a: ";
    a.show();
    std::cout << "b: ";
    b.show();
    std::cout << "c: ";
    c.show();
    std::cout << "==================" << std::endl;
    a = b + c;
    std::cout << "a: ";
    a.show();
    std::cout << "b: ";
    b.show();
    std::cout << "c: ";
    c.show();
    return 0;
}

Консоль:
a: 0 m 0 cm
b: 5 m 40 cm
c: 5 m 60 cm
==================
a: 11 m 0 cm
b: 11 m 0 cm
c: 5 m 60 cm

Как можем заметить переменная b изменилась, что является неожиданным моментом работы кода.
Поэтому в (1) и создается локальный объект, чтобы предотвратить возможное поведение.
Просмотры: 47
Перейти в пост Открыть в MAX Сообщить о неточности
Основное из главы 11. Прата.
Перегрузка операций с помощью operate,  основная суть в том, что можем использовать стандартные операторы (+, -, *, << и так далее) с пользовательскими объектами класса.
Перегрузка операций.

class Distance {
private:
    int meters;
    int centimeters;
public:
    Distance(int m = 0, int cm = 0) : meters(m), centimeters(cm) {}
    //(1)
    Distance operator+(const Distance & other) const {
        Distance result;
        result.centimeters = centimeters + other.centimeters;
        result.meters = meters + other.meters + result.centimeters / 100;
        result.centimeters %= 100;
        return result;
    }
    //(2)
    Distance operator-(const Distance & other) const {
        int total1 = meters * 100 + centimeters;
        int total2 = other.meters * 100 + other.centimeters;
        int diff = total1 - total2;
        return Distance(diff / 100, diff % 100);
    }
    //(3)
    Distance operator*(double factor) const {
        double total = (meters * 100 + centimeters) * factor;
        int totalCm = int(total + 0.5);
        return Distance(totalCm / 100, totalCm % 100);
    }
   
    void show() const {
        std::cout << meters << " m " << centimeters << " cm";
    }
};

(1) Принцип работы operator. Можно поделить выражение (такое
как a = a + b или c = a + b) на две части: левую и правую. Как раз-таки мы работаем с левой частью, то есть “a”, чтобы было попроще можно это объяснить по другому: мы перегружаем “+”значит левая часть будет слева от “+”, потому что может быть и такое выражение – d = a+ b + c (или для упрощения d = ((a + b)+c) ), что значит первая левая часть будет “a”( a.operator+(b)), а после – “a+b” ((a + b).operator+(c)). Здесь есть один из важных моментов. Как мы можем наблюдать, то operator+ возвращаем константный объект типа Distance. Может показаться, что можно было бы сделать код проще и эффективнее, то есть не создавать локальный объект Distance result, а сразу же изменять левую часть. То есть записать следующим образом:
(4)

Distance Distance::operator+(const Distance& other) {
    centimeters = centimeters + other.centimeters;
    meters += other.meters + centimeters / 100;
    centimeters %= 100;
    return *this;
}

Для понимания, что делается в коде (4). Складываем сантиметры centimeters, после вычисляем метры (складываем метры с метрами) и делим сантиметры на 100, чтобы получить метры с сантиметров. Далее, чтобы убираем «лишние сантиметры» с помощью деления на модуль (допустим у нас скопилось 132 снатиметра, 132 % 100 = 32 осталось, 100 сантиметров ушло).

А теперь, тот важный момент (4). Мы сразу изменяем левый операнд и его возвращаем, тогда получается следующая ситуация, допустим, у нас есть выражение a =  b + c, тогда операнд b изменятся, посмотрим:
Просмотры: 39
Перейти в пост Открыть в MAX Сообщить о неточности
В начале, в принципе, нет чего-то сложного, простое определение класса.
Здесь имеется 3 конструктора, первый по умолчанию (когда мы просто объявляем объект, например, STORE::Product p1). Второй уже параметризированный, с двумя переменными по умолчанию, а третий конструктор необходим для присваивания одного объекта другому.
Также, для примера есть 3 перегрузки (с ключевым словом operator) операций (1 из них дружественная функция) и 3 метода. Все они выполняют по сути одно и тоже.

Основной момент по третьей перегрузке со знаком = (operator=). Тут случай когда мы объект, допустим, p1 приравниваем к p2. Здесь есть неявное this (указание на объект p1), например, строчка m_name = another.m_name можно представить как this.m_name = another.m_name. Также есть важный момент правило трех «Если класс явно определяет хотя бы один из трёх специальных методов – деструктор, конструктор копирования или оператор присваивания копированием, – то он почти наверняка должен явно определить и два других.» для переменной m_discount в Product::Product(const Product& another) выделяется область памяти, если это не сделать, то объекты будут ссылаться на один и тот же адрес и при уничтожении объекта возникнет двойное удаление, что приведет к аварийному завершению программы, также в operator= при присваивании освобождается память, выделяется новая с копированием из другого объекта, если пропустить  delete, то произойдёт утечка памяти (по сути программа будет просто забирать память и не сможет с ней взаимоджействовать).

На что стоит обратить внимание: static int totalProducts, данную переменную (она необходима для подсчета «живых сущностей») будет необходимо инициализировать в файле .cpp нулем. Насчёт её поведения пока ничего не могу сказать, если допустим определить переменную в объявлении, то как она себя поведёт в двух разных .cpp файлах.

Методы:
void sell(int amount) – уменьшает количество товаров, соответственно изменяется и m_totalPrice
void restock(int amount)
– похож на метод выше, только делает все наоборот.
void show() const – показывает содержание объекта.
void setDiscount(double discount) – устанавливает в объект скидку, соответственно изменяется и m_totalPrice
void setTotalPrice()
– считает общую сумму
static int getTotalProducts() – возвращает количество «живых сущностей».
 
Программа, вывод в консоли.
Создаётся объект p1 необходимо инициализировать с STORE::, так как Product находится в пространстве имен  STORE. Дальше используем методы sell, restock и show.
В блоке создаётся p2, также используем using, чтобы для Product не объявлять STORE::, что мы и видим при объявлении p2. После того как блок заканчивается, то объект уничтожается. Это можно увидеть, когда мы STORE::Product::getTotalProducts() будет выведено 1, а не 2, так как блок закончился, то объект уничтожился.
Дальше используем перегрузки операций.

Name: UnknownName
Price: 0
Quantity: 0
Discount: 0
Total price: 0
Obj #1
-----------------------
QUANTITY IS NOT ENOUGH
-----------------------
Name: UnknownName
Price: 0
Quantity: 100
Discount: 0
Total price: 0
Obj #1
-----------------------
Name: Internal block
Price: 0
Quantity: 0
Discount: 0
Total price: 0
Obj #2
-----------------------
NUMBER OF OBJECTS: 1
-----------------------
Name: Jojo
Price: 1000
Quantity: 75
Discount: 0
Total price: 75000
Obj #2
-----------------------
Name: Jojo
Price: 1000
Quantity: 75
Discount: 0.3
Total price: 52500
Obj #2
-----------------------
Name: Jojo
Price: 1000
Quantity: 75
Discount: 0.3
Total price: 52500
Obj #1
-----------------------
NUMBER OF OBJECTS: 2
Просмотры: 106
Перейти в пост Открыть в MAX Сообщить о неточности
file.cpp

#include <iostream>
#include <string>
#include "file_h.h"

namespace STORE {
    int Product::totalProducts = 0;
    Product::Product() {
        totalProducts++;
        m_name = "UnknownName";
        m_price = 0.0;
        m_quantity = 0;
        m_discount = new double(0.0);
        m_obj = totalProducts;
        setTotalPrice();
    }

    Product::Product(std::string name, double price, int quantity) {
        totalProducts++;
        m_name = name;
        m_price = price;
        m_quantity = quantity;
        m_discount = new double(0.0);
        m_obj = totalProducts;
        setTotalPrice();
    }
   
    Product::Product(const Product& another) {
        totalProducts++;
        m_name = another.m_name;
        m_price = another.m_price;
        m_quantity = another.m_quantity;
        m_discount = new double(*(another.m_discount));
        m_obj = totalProducts;
        m_totalPrice = another.m_totalPrice;
    };


    Product::~Product() {
        delete m_discount;
        totalProducts--;
    }

    void Product::sell(int amount) {
        if(m_quantity >= amount) {
            m_quantity -= amount;
        } else {
            std::cout << "QUANTITY IS NOT ENOUGH" << std::endl
                << "-----------------------" << std::endl;            ;
        }
        setTotalPrice();
    }

    void Product::restock(int amount) {
        m_quantity += amount;
        setTotalPrice();
    }

    void Product::show() const {
        std::cout << "Name: " << m_name << std::endl
                  << "Price: " << m_price << std::endl
                  << "Quantity: " << m_quantity << std::endl
                  << "Discount: " << *(m_discount) << std::endl
                  << "Total price: " << m_totalPrice << std::endl
                  << "Obj #" << m_obj << std::endl
                  << "-----------------------" << std::endl;
    }    

    void Product::setDiscount(double discount) {
        *m_discount = discount;
        setTotalPrice();
    }

    void Product::setTotalPrice() {
        m_totalPrice = (1 - *m_discount) * m_price * m_quantity;
    }

    Product& Product::operator=(const Product& another) {
        if(this == &another) {
            return *this;
        }

        m_name = another.m_name;
        m_price = another.m_price;
        m_quantity = another.m_quantity;
        delete m_discount;
        m_discount = new double(*(another.m_discount));
        m_totalPrice = another.m_totalPrice;
        return *this;
    }

    Product& Product::operator+=(int amount) {
        m_quantity += amount;
        setTotalPrice();
        return *this;
    }

    std::ostream& operator<<(std::ostream& os, const Product& p) {
        os << "Name: " << p.m_name << std::endl
            << "Price: " << p.m_price << std::endl
            << "Quantity: " << p.m_quantity << std::endl
            << "Discount: " << *p.m_discount << std::endl
            << "Total price: " << p.m_totalPrice << std::endl
            << "Obj #" << p.m_obj << std::endl
            << "-----------------------" << std::endl;
        return os;
    }
};


int main() {
    STORE::Product p1;
    p1w.sho();
    p1.sell(10);
    p1.restock(100);
    p1w.sho();

    {
        using STORE::Product;
        Product p2("Internal block");
        p2.show
();
    }

    std::cout << "NUMBER OF OBJECTS: " << STORE::Product::getTotalProducts() << std::endl;
    std::cout << "-----------------------" << std::endl;

    STORE::Product p3("Jojo", 1000, 20);
    p3 += 55;
    std::cout << p3;
    p3.setDiscount(0.3);
    std::cout << p3;

    p1 = p3;
    std::cout << p1;

    std::cout << "NUMBER OF OBJECTS: " << STORE::Product::getTotalProducts() << std::endl;
    return 0;
}
Просмотры: 90
Перейти в пост Открыть в MAX Сообщить о неточности
Вся лента — после бесплатной регистрации
ВКонтакте Телеграм Одноклассники
Избранное в datool.ru

Следите за каналом в личном кабинете

Зарегистрируйтесь в datool.ru, чтобы добавить канал «Я просто спросить про указатели C++ (изучаю С++).» в избранное и отслеживать его показатели.

Зарегистрироваться
Для владельцев каналов

Подтвердите свой канал

Войдите или зарегистрируйтесь в datool.ru, затем добавьте нашего бота в канал по инструкции в личном кабинете. После проверки владения замок исчезнет и вам станет доступно управление каналом.

Войти или зарегистрироваться

Сообщить о неточности

Опишите, что нужно исправить. Если есть источник, добавьте ссылку.

Вы покидаете datool.ru

Ссылка ведёт на внешний сайт. datool.ru не отвечает за его содержимое — проверьте адрес, прежде чем вводить пароли или платёжные данные.

Переход через 10 с

Перейти