моя контактная информация
Почтамезофия@protonmail.com
2024-07-12
한어Русский языкEnglishFrançaisIndonesianSanskrit日本語DeutschPortuguêsΕλληνικάespañolItalianoSuomalainenLatina
Оглавление
2.1 Концепция создания экземпляров
4. Функции-члены классов по умолчанию.
Формат определения класса
class — ключевое слово, определяющее класс, Stack — имя класса, а {} — тело класса. Обратите внимание, что точка с запятой в конце определения не опускается. Содержимое тела класса называется членами класса: переменные в классе называются атрибутами, а переменные-члены класса называются методами или функциями-членами класса;
- //text.cpp
- #include<iostream>
- using namespace std;
-
- class Stack
- {
-
- //成员变量
- int* a;
- int top;
- int capacity;
- //成员函数
- void Push()
- {
-
- }
- void Pop()
- {
-
- }
- };//分号不能省略
- int main()
- {
-
-
- return 0;
- }
- //为区分成员变量,一般前面加_
- //成员变量
- int* _a;
- int _top;
- int _capacity;
C++ — это способ реализовать инкапсуляцию, используя классы для объединения свойств и методов объекта, чтобы сделать объект более полным, и выборочно предоставлять его интерфейс внешним пользователям через права доступа.
- //text.cpp
- #include<iostream>
- using namespace std;
-
- class Stack
- {
-
-
- ///
-
- void Push()
- {
-
- }
- //Push 没给限定符 class默认私有 private
- ///
- public:
- void Pop()
- {
-
- }
- int Swap()
- {
-
- }
- //Pop和Swap 被public修饰,直到下一个限定符出现之前都为公有
- ///
- protected:
- int add();
- //add 被public修饰,直到下一个限定符出现之前都为保护
- /// /
-
- private:
-
- int* _a;
- int _top;
- int _capacity;
- //成员变量被private修饰,直到}结束都为私有
- };
- int main()
- {
- Stack st;
- //公有可以访问
- st.Pop();
- st.Swap();
- //私有不可访问
- st._top;
-
-
-
- return 0;
- }
Дополнительные замечания:
Класс определяет новую область видимости. Все члены класса находятся в области видимости класса. При определении членов вне класса необходимо использовать оператор ::scope, чтобы указать, к какой области класса принадлежит элемент.
Домен класса влияет на правила поиска компиляции. Если в Init в следующей программе не указан стек домена класса, компилятор будет рассматривать Init как глобальную функцию. Если во время компиляции он не сможет найти такие члены, как _top, он перейдет к функции. домен класса, чтобы найти их.
- //text.cpp
- #include<iostream>
- using namespace std;
-
- class Stack
- {
-
-
- public:
- void Init(int x, int y);
-
- };
- void Stack::Init(int x, int y)
-
- {
- _top = x;
- _capacity = y;
- }
- int main()
- {
-
- return 0;
- }
Уведомление:
- //text.cpp
- #include<iostream>
- using namespace std;
-
- class Stack
- {
-
- //声明
-
- int* _a;
- int _top;
- int _capacity;
-
- };
-
- int main()
- {
-
- Stack::_top = 2024;
- //编译器报错,_top只是声明,并未实例化
-
- return 0;
- }
-
- //text.cpp
- #include<iostream>
- using namespace std;
-
- class Stack
- {
-
-
- //声明
- int* _a;
- int _top;
- int _capacity;
-
- };
-
- int main()
- {
-
-
- Stack st;
- st._top=2024;
- //Stack实例化出st,系统已经给st分配内存了,可以存储数据,编译通过
-
- return 0;
- }
-
-
Правила выравнивания памяти
- class A
- {
- public:
- void Print()
- {
- cout << _ch << endl;
- }
- private:
- char _ch;
-
- int _i;
- };
- //_ch 是一个字节,默认对齐数是4,最大对齐数是4,所以开辟4个字节用来存在_ch
- // _i是4个字节,默认对齐数是4,最大对齐数是4,所以开辟4个字节用来存储_i
- class B
- {
- public:
- void Print()
- {
- //。。。
- }
-
-
- };
- class B
- {
-
-
- };
- //B和C里面没有存储任何成员变量,只有一个函数,可成员函数不存对象里面
- // 按理来说是0,但是结构体怎么会没大小,为表示对象存在C++对这种规定大小为1,为了占位标识对象存在
После компиляции компилятора функции-члены класса по умолчанию добавят указатель на текущий класс в первую позицию формального параметра, называемого этим указателем.
Например, прототипом Init в классе Date является void Init (Date * const this, int Year, int Month, Int Day. При доступе к переменным-членам в функциях-членах класса доступ к сути осуществляется через указатель this. например, _year в функции Init, this->_year=year.
опытный образец:
- class Date
- {
- void Print()
- {
-
- cout << _year << "n" << _month << "n" << _day << endl;
- }
- void Init( int year, int month,int day)
- {
- _year = year;
- _month = month;
- _day = day;
-
- }
-
- private:
- int _year;
- int _month;
- int _day;
-
- };
-
- Date d1;
- d1.Init(2024,7,10);
-
- d1.Print();
- Date d2;
-
- d2.Init(2024, 7, 9);
- d2.Print();
-
реальный прототип
- class Date
- {
- void Init(Date* const this,int year, int month,int day)
-
- {
- this->_year = year;
- this->_month = month;
- this->_day = day;
-
- }
- void Printf(Date* const this)
-
- {
-
- cout << this->_year << "n" <<this-> _month << "n" << this->_day << endl;
- }
- private:
- int _year;
- int _month;
- int _day;
-
- };
- Date d1;
- d1.Init(&d1,2024,7,10);
- d1.Print(&d1);
-
- Date d2;
- d2.Init(&d2,2024, 7, 9);
- d2.Print();
В C++ предусмотрено, что этот указатель нельзя записывать в позиции фактических параметров и формальных параметров (компилятор будет обрабатывать его при компиляции), но этот указатель можно использовать явно в теле функции. Этот указатель нельзя изменить, но его нельзя изменить. содержимое, на которое указывает этот указатель, может
этот указатель хранится в стеке
Функция-член по умолчанию — это функция-член, которая не определена явно пользователем и автоматически генерируется компилятором. Она называется функцией-членом по умолчанию.
Конструктор — это специальная функция-член. Следует отметить, что хотя конструктор и называется конструктором, основное его содержание — это не открытие места для создания объектов (обычно мы используем локальный объект — это пространство, которое открывается при создается кадр стека)), но объект инициализируется при создании экземпляра объекта. Суть конструктора заключается в замене функции Init, которую мы написали ранее в классах Stack и Date. Автоматический вызов конструктора прекрасно заменяет функцию Init.
Особенности конструктора:
- class Date
- {public:
- //1.无参构造函数
- Date()
- {
- _year = 1;
- _month = 1;
- _day = 1;
- }
- //2.带参构造函数
- Date(int year, int month, int day)
- {
- _year = year;
- _month = month;
- _day = day;
- }
-
-
- //3.全缺省构造函数
- Date(int year = 1, int month = 1, int day = 1)
- {
- _year = year;
- _month = month;
- _day = day;
- }
- private:
- int _year;
- int _month;
- int _day;
-
- };
Конструктор без параметров, конструктор по умолчанию и конструктор, создаваемый компилятором по умолчанию, когда мы не пишем конструктор, — все они называются конструкторами по умолчанию. Но из этих троих может существовать только один, но не одновременно. Хотя конструктор без параметров и полный конструктор по умолчанию представляют собой перегрузку функции, при их вызове может возникнуть неоднозначность.Обратите внимание, что не только конструктор по умолчанию генерируется компилятором по умолчанию, это конструктор, конструктор без параметров, а полный конструктор по умолчанию также является конструктором по умолчанию. Подводя итог, его можно вызывать без передачи параметров.
Мы его не пишем, конструкция, сгенерированная компилятором по умолчанию, не имеет требований к инициализации переменных-членов встроенного типа. То есть, инициализирована она или нет — неясно, это зависит от компилятора.
- //text.cpp
- #include<iostream>
- using namespace std;
- typedef int STDataType;
- class Stack
- {
- public:
- Stack(int n = 4)
- {
- _a = (STDataType*)malloc(sizeof(STDataType) * n);
- if (nullptr == _a)
- {
- perror("malloc申请失败");
- }
- _capacity = n;
- _top = 0;
- }
-
- private:
- STDataType* _a;
- size_t _capacity;
- size_t _top;
- };
- //两个Stack实现队列
- class MyQueue
- {
- private:
- int size;
- Stack pushst;
- Stack popst;
- };
-
- int main()
- {
-
- MyQueue my;
-
-
- return 0;
- }
-
В C++ типы делятся на пользовательские и встроенные (базовые типы). Встроенные типы — это собственные типы данных, предоставляемые языком, например int/char/double/pointer и т. д. Пользовательские типы — это типы, которые мы определяем сами, используя такие ключевые слова, как class/struct.Конструктор здесь инициализируется автоматически, а VS также инициализирует размер встроенного типа. Разные компиляторы имеют разные значения инициализации, и C++ их не задает.
Для переменных-членов пользовательского типа необходимо вызвать конструктор по умолчанию этой переменной-члена для ее инициализации.Если у этой переменной-члена нет конструктора по умолчанию, будет сообщено об ошибке. Если мы хотим инициализировать эту переменную-член, нам нужно использовать список инициализации для ее решения.
Резюме: В большинстве случаев нам необходимо реализовать конструктор самостоятельно. В некоторых случаях он похож на MyQueue, и когда у Stack есть конструктор по умолчанию, MyQueue может быть автоматически сгенерирован и использован.
- ~Stack()
- {
- free(_a);
- _a = nullptr;
- _top = _capacity = 0;
- }
Характеристики деструктора:
1. Имени деструктора предшествуют символы~
2. Никаких параметров и возвращаемого значения (согласно конструктору).
3. Класс может иметь только один деструктор.Если определение не отображается, система автоматически сгенерирует деструктор по умолчанию.
4. Когда цикл объявления объекта завершится, система автоматически вызовет деструктор.
5. Как и в случае с конструктором, мы не пишем деструктор, автоматически сгенерированный компилятором, и не обрабатываем члены встроенного типа. Члены пользовательского типа будут вызывать другие деструкторы.
6. Следует также отметить, что когда мы отображаем деструктор, также будет вызываться деструктор члена пользовательского типа, а это означает, что деструктор члена пользовательского типа будет вызываться автоматически независимо от ситуации.
- //text.cpp
- #include<iostream>
- using namespace std;
- typedef int STDataType;
- class Stack
- {
- public:
- Stack(int n = 4)
- {
- _a = (STDataType*)malloc(sizeof(STDataType) * n);
- if (nullptr == _a)
- {
- perror("malloc申请失败");
- }
- _capacity = n;
- _top = 0;
-
-
- }
-
- ~Stack()
- {
- free(_a);
- _a = nullptr;
- _top=_capacity=0;
- }
- private:
- STDataType* _a;
- size_t _capacity;
- size_t _top;
-
- };
- //两个Stack实现队列
- class MyQueue
- {public:
- //编译器默认生成MyQueue的构造函数调用了Stack的构造,完成了两个成员的初始化
- //编译器默认生成MyQueue的析构函数调用了Stack的析构,释放了Stack内部的资源
- //显示写析构也会调用Stack的析构
- ~MyQueue()
- {
- cout << "~MyQueue" << endl;
- }
- private:
-
- Stack pushst;
- Stack popst;
-
- };
-
-
- int main()
- {
-
- MyQueue my;
-
-
- return 0;
- }
Деструктор в MyQueue ничего не делает, но C++ предусматривает, что для освобождения памяти будут вызываться другие деструкторы.
Если никакие ресурсы не запрашиваются, деструктор не нужно записывать, и можно напрямую использовать деструктор по умолчанию, сгенерированный компилятором, например Date. Если можно использовать сгенерированный деструктор по умолчанию, нет необходимости явно записывать деструктор. например MyQueue, но есть ресурсное приложение. При деструкции обязательно напишите деструктор напрямую, иначе это приведет к утечке ресурсов, например Stack.
-
-
- bool operator<(Date d1, Date d2)
- {
-
- }
- bool operator==(Date d1,Date d2)
- {
- return d1._year == d2._year && d1._month == d2._month && d1._day == d2._day;
- }
- //text.cpp
- #include<iostream>
- using namespace std;
-
- class Date
- {
- public:
- Date(int year, int month, int day)
- {
- _year= year;
- _month = month;
- _day = day;
-
- }
-
-
-
- int _year;
- int _month;
- int _day;
-
- };
-
- bool operator<(Date d1, Date d2)
- {
-
- }
- bool operator==(Date d1,Date d2)
- {
- return d1._year == d2._year && d1._month == d2._month && d1._day == d2._day;
- }
- int main()
- {
-
- Date d1(2024, 7, 10);
- Date d2(2024,7,9);
- //两种用法都可以
- d1 == d2;
- operator==(d1 , d2);
- return 0;
- }