Обмен технологиями

Список инициализации конструктора, статических членов, друзей, внутренних классов [Классы и объекты (Часть 2)]

2024-07-12

한어Русский языкEnglishFrançaisIndonesianSanskrit日本語DeutschPortuguêsΕλληνικάespañolItalianoSuomalainenLatina

PS: Следующий код был протестирован в среде VS2022, что не означает, что все компиляторы смогут его пройти.
PS: Ни один из тестовых кодов не отображает объявление заголовочного файла stdio.h. Добавьте его самостоятельно при его использовании.

  

Вставьте сюда описание изображения

                                           Домашняя страница блоггера: LiUEEEEE
                                                Столбец С++
                                              Столбец языка C
                                            Столбец структуры данных
                                            Столбец алгоритма сортировки
                                         Колонка на классические темы Ниуке

1. Список инициализации конструктора

1.1 Взглянем на конструктор


В моем предыдущем блоге

          Создание, уничтожение, копирование [Классы и объекты (Часть 2)]
Конструктор класса упоминается в . На примере класса date метод инициализации выглядит следующим образом:

class Date
{
public:
	Date(int year, int month, int day)
	{
		_year = year;
		_month = month;
		_day = day;
	}
private:
	int _year;
	int _month;
	int _day;
};
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14

Как показано в приведенном выше коде, без дальнейшего изучения C++ пользователи обычно думают, что код в конструкторе представляет собой инициализацию переменных-членов класса, но на самом деле все наоборот. В C++ инициализируется только основной оператор конструктора. Присваивание переменных-членов нельзя назвать инициализацией в истинном смысле, поскольку инициализацию можно инициализировать только один раз, в то время как конструктор может присваивать значения переменным-членам несколько раз, например:

	Date(int year, int month, int day)
	{
		_year = year;
		_year += 1;
	}
  • 1
  • 2
  • 3
  • 4
  • 5

1.2 Список инициализации


В настоящее время представлен список инициализации в C++.
Список инициализации — это список элементов данных, начинающийся с «:» (двоеточие) и разделенный «,» (запятая). За каждой переменной-членом следует скобка, а значение, помещенное в скобку, является, например, инициализированным значением. :
	Date(int year, int month, int day)
		: _year(year)
		, _month(month)
		, _day(day)
	{}
  • 1
  • 2
  • 3
  • 4
  • 5

нужно знать, это:

  1. Каждая переменная-член может появиться в списке инициализации только один раз (инициализацию можно инициализировать только один раз).
  2. Класс содержит следующие члены, которые для инициализации необходимо поместить в список инициализации:
    • Ссылка на переменные-члены
    • Переменные-члены пользовательского типа (а у пользовательского типа нет конструктора по умолчанию: конструктор без параметров, конструктор полностью по умолчанию, конструктор, автоматически создаваемый системой)
    • константные измененные переменные-члены

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

1.3 Советы по списку инициализации


При написании списка инициализации порядок инициализации переменных-членов должен соответствовать порядку объявления в классе, поскольку компилятор инициализирует переменные последовательно в соответствии с порядком объявления. Если пользователь не запишет в порядке, это вызовет ошибку. ненужные хлопоты, такие как:
class A
{
public:
	A(int n)
		:_a2(n)
		,_a1(_a2)
	{}
	void Print()
	{
		cout << "_a1 = " << _a1 << endl;
		cout << "_a2 = " << _a2 << endl;
	}
private:
	int _a1;
	int _a2;
};

int main()
{
	A aa(100);
	aa.Print();

	return 0;
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24

Вставьте сюда описание изображения
При инициализации, как показано на рисунке выше, будут достигнуты результаты, не соответствующие ожиданиям, поэтому при его использовании следует избегать таких операций.



2. явное ключевое слово


Для конструктора также есть функция, предназначенная дляконструктор с одним параметромилиКонструктор с несколькими параметрами, но без значения по умолчанию для первого параметра.Неявное преобразование типов, например:
class Date
{
public:
	Date(int year)
		: _year(year)
	{}
	Date& operator=(const Date& d)
	{
		if (this != &d)
		{
			_year = d._year;
			_month = d._month;
			_day = d._day;
		}
		return *this;
	}
private:
	int _year;
	int _month;
	int _day;
};
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
class Date
{
public:
	Date(int year, int month = 1, int day = 1)
		: _year(year)
		, _month(month)
		, _day(day)
	{}
	Date& operator=(const Date& d)
	{
		if (this != &d)
		{
			_year = d._year;
			_month = d._month;
			_day = d._day;
		}
		return *this;
	}
private:
	int _year;
	int _month;
	int _day;
};
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23

При назначении путем передачи значения, например:

	Date date(2024);
  • 1

На уровне компилятора 2024 не присваивается напрямую созданному объекту класса, а преобразуется во временный объект класса посредством неявного преобразования, а затем присваивается объекту класса, который необходимо инициализировать через такой объект. необходимо. Инициализированный объект класса — A, а временный объект класса — B:

	Date A(2024);
	等价于
	Date A = B//B的值为2024
  • 1
  • 2
  • 3

Чтобы избежать неявного преобразования, в C++ создано ключевое слово «explicit». Добавление «explicit» перед конструктором может предотвратить неявное преобразование, например:
	explicit Date(int year)
		: _year(year)
	{}
  • 1
  • 2
  • 3




3. статические члены

3.1 концепция статического члена


Члены класса, объявленные как статические, называются статическими членами класса. Переменные-члены, измененные с помощью static, называются статическими переменными-членами; функции-члены, измененные с помощью static, называются статическими функциями-членами. Статические переменные-члены должны быть инициализированы вне класса, например:
class Date
{
public:
	Date(int year, int month = 1, int day = 1)
		: _year(year)
		, _month(month)
		, _day(day)
	{}
private:
	int _year;
	int _month;
	int _day;
	static int _i;
};

int Date::_i = 1;
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16

3.2 статические характеристики члена


  1. Статические члены являются общими для всех объектов класса и не принадлежат конкретному объекту. Они хранятся в статической области.
  2. Статические переменные-члены должны быть определены вне класса. Ключевое слово static не добавляется при определении. Оно просто объявляется в классе.
  3. Доступ к статическим членам класса можно получить, используя имя класса::статический член или объект.статический член.
  4. Статические функции-члены не имеют скрытого указателя и не могут получить доступ к нестатическим членам.
  5. Статические члены также являются членами класса и ограничены квалификаторами доступа public, protected и Private.




4. Ююань


Друзья предоставляют возможность обойти инкапсуляцию и иногда обеспечивают удобство. Однако друзья увеличивают связанность и разрушают инкапсуляцию, поэтому друзей не следует использовать более одного раза.

Друзья делятся на: функции друзей и классы друзей.

4.1 Функции друга


Дружественная функция означает, что когда функции вне класса требуется доступ к закрытому члену класса, к ней можно получить доступ, объявив эту функцию в классе как дружественную функцию класса, например:
class Date
{
	friend void Print(Date& d);
public:
	Date(int year = 1, int month = 1, int day = 1)
		: _year(year)
		, _month(month)
		, _day(day)
	{}
private:
	int _year;
	int _month;
	int _day;
};
void Print(Date& d)
{
	cout << d._year << " " << d._month << " " << d._day <<endl;
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • Дружественные функции могут иметь доступ к частным и защищенным членам класса, но не к функциям-членам класса.
  • Дружественные функции не могут быть изменены с помощью const
  • Дружественные функции могут быть объявлены в любом месте определения класса и не ограничены квалификаторами доступа к классу.
  • Функция может быть дружественной функцией нескольких классов.
  • Принцип вызова дружественных функций такой же, как и у обычных функций.

4.2 Классы друзей


Когда класс хочет получить доступ к закрытым членам другого класса, он может объявить этот класс другом в классе, к которому требуется доступ, а затем получить доступ к его закрытым членам, например:
class Time
{
	friend class Date; // 声明日期类为时间类的友元类,则在日期类中就直接访问Time类
					   //中的私有成员变量
public:
	Time(int hour = 0, int minute = 0, int second = 0)
			: _hour(hour)
			, _minute(minute)
			, _second(second)
	{}
private:
	int _hour;
	int _minute;
	int _second;
};
class Date
{
public:
	Date(int year = 1900, int month = 1, int day = 1)
			: _year(year)
			, _month(month)
			, _day(day)
	{}	
	void SetTimeOfDate(int hour, int minute, int second)
	{
		// 直接访问时间类私有的成员变量
		_t._hour = hour;
		_t._minute = minute;
		_t._second = second;
	}
private:
	int _year;
	int _month;
	int _day;
	Time _t;
};
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • Дружеские отношения односторонние и некоммутативные. Например, в вышеупомянутых классах Time и Date, если вы объявите класс Date как его дружественный класс в классе Time, вы сможете напрямую получить доступ к закрытым переменным-членам класса Time в классе Date, но вы хотите получить доступ к закрытым переменным-членам класса Date в классе Time No.
  • Дружеские отношения не могут быть транзитивными. Если C — друг B, а B — друг A, это не может означать, что C — друг A.




5. Внутренний класс


C++ поддерживает создание другого класса внутри класса, который называется внутренним классом. Внутренний класс является независимым классом. Он не принадлежит внешнему классу, и к членам внутреннего класса нельзя получить доступ через объекты внешнего класса. . Внешний класс не имеет превосходного доступа к внутреннему классу.
И внутренний класс, естественно, является другом внешнего класса, то есть внутренний класс может получить доступ к закрытым членам внешнего класса.

характеристика:

  1. Внутренние классы могут быть определены как общедоступные, защищенные или частные во внешних классах.
  2. Обратите внимание, что внутренние классы могут напрямую обращаться к статическим членам внешних классов, не требуя имени объекта/класса внешнего класса.
  3. sizeof(external class)=внешний класс, не имеет ничего общего с внутренними классами.




6. Заключение


Вставьте сюда описание изображения

  Большое спасибо за просмотр моей оригинальной статьи.
  Эта статья в основном используется для личного обучения и обмена знаниями. Путь обучения долгий. Если есть какие-либо ошибки, спасибо, что исправили меня.
  Если нужно цитировать, укажите адрес.