Partage de technologie

Liste d'initialisation du constructeur, des membres statiques, des amis, des classes internes [Classes et objets (Partie 2)]

2024-07-12

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

PS : Le code suivant a été testé dans l'environnement VS2022, ce qui ne veut pas dire que tous les compilateurs peuvent le transmettre.
PS : aucun des codes de test n'affiche la déclaration du fichier d'en-tête stdio.h. Veuillez l'ajouter vous-même lors de son utilisation.

  

Insérer la description de l'image ici

                                           Page d'accueil du blogueur : LiUEEEEE
                                                Colonne C++
                                              Colonne du langage C
                                            Colonne de structure de données
                                            Colonne d'algorithme de tri
                                         Chronique sur des sujets classiques de Niuke

1. Liste d'initialisation du constructeur

1.1 Retour sur le constructeur


Dans mon blog précédent

          Construction, destruction, copie [Classes et objets (Partie 2)]
Le constructeur de la classe est mentionné dans. En prenant la classe date comme exemple, la méthode d'initialisation est la suivante :

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

Comme le montre le code ci-dessus, sans étude plus approfondie du C++, les utilisateurs penseront généralement que le code du constructeur est l'initialisation des variables membres de la classe, mais le fait est exactement le contraire. En C++, l'instruction principale du constructeur s'initialise uniquement. les variables membres. L'affectation ne peut pas être appelée initialisation dans le vrai sens du terme, car l'initialisation ne peut être initialisée qu'une seule fois, tandis que le constructeur peut attribuer des valeurs aux variables membres plusieurs fois, par exemple :

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

1.2 Liste d'initialisation


A cette époque, la liste d'initialisation en C++ est introduite.
La liste d'initialisation est une liste de données membres commençant par ":" (deux-points) et séparés par "," (virgule). Chaque variable membre est suivie d'une parenthèse et la valeur placée entre parenthèses est la valeur initialisée, par exemple. :
	Date(int year, int month, int day)
		: _year(year)
		, _month(month)
		, _day(day)
	{}
  • 1
  • 2
  • 3
  • 4
  • 5

il faut être conscient de ce qui suit :

  1. Chaque variable membre ne peut apparaître qu'une seule fois dans la liste d'initialisation (l'initialisation ne peut être initialisée qu'une seule fois)
  2. La classe contient les membres suivants, qui doivent être placés dans la liste d'initialisation pour l'initialisation :
    • Variables de membre de référence
    • Variables membres de type personnalisé (et le type personnalisé n'a pas de constructeur par défaut : un constructeur sans paramètre, un constructeur entièrement par défaut, un constructeur généré automatiquement par le système)
    • variables membres modifiées const

Les variables membres personnalisées mentionnées ci-dessus (sans constructeur par défaut) signifient que le constructeur de la variable membre personnalisée définie est un constructeur avec des paramètres, et les paramètres doivent être transmis avant de pouvoir être initialisé lorsque l'utilisateur affiche le constructeur, si l'initialisation est effectuée. La liste n'est pas écrite, le compilateur la générera automatiquement pour l'utilisateur. Cependant, si l'initialisation des variables membres personnalisées nécessite la participation de paramètres, le système ne transmettra pas les paramètres par défaut, ce qui entraînera une non-initialisation. pour éviter une situation de désinitialisation afin d'éviter des problèmes inutiles lors d'une utilisation ultérieure.

1.3 Conseils sur la liste d'initialisation


Lors de l'écriture de la liste d'initialisation, l'ordre d'initialisation des variables membres doit être cohérent avec l'ordre de déclaration dans la classe, car le compilateur initialise les variables dans l'ordre selon l'ordre de déclaration, si l'utilisateur n'écrit pas dans l'ordre, cela entraînera. des ennuis inutiles, tels que :
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

Insérer la description de l'image ici
Lorsqu'il est initialisé comme le montre la figure ci-dessus, des résultats incompatibles avec les attentes seront obtenus, de telles opérations doivent donc être évitées lors de son utilisation.



2. mot-clé explicite


Pour le constructeur, il existe également une fonction dédiée àconstructeur à paramètre uniqueouConstructeur avec plusieurs paramètres mais pas de valeur par défaut pour le premier paramètreConversion de type implicite, par exemple :
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

Lors d'une attribution en passant une valeur, par exemple :

	Date date(2024);
  • 1

Au niveau du compilateur, 2024 n'est pas directement affecté à l'objet de classe créé, mais 2024 est converti en objet de classe temporaire par conversion implicite, puis attribué à l'objet de classe qui doit être initialisé via un tel objet. est nécessaire L'objet de classe initialisé est A et l'objet de classe temporaire est B :

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

Afin d'éviter la conversion implicite, C++ a créé le mot-clé explicit en ajoutant explicit avant que le constructeur puisse empêcher la conversion implicite, par exemple :
	explicit Date(int year)
		: _year(year)
	{}
  • 1
  • 2
  • 3




3. membres statiques

3.1 Concept de barre statique


Les membres de classe déclarés comme statiques sont appelés membres statiques de la classe. Les variables membres modifiées avec static sont appelées variables membres statiques ; les fonctions membres modifiées avec static sont appelées fonctions membres statiques. Les variables membres statiques doivent être initialisées en dehors de la classe, par exemple :
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 Caractéristiques des éléments statiques


  1. Les membres statiques sont partagés par tous les objets de classe et n'appartiennent pas à un objet spécifique. Ils sont stockés dans la zone statique.
  2. Les variables membres statiques doivent être définies en dehors de la classe. Le mot-clé static n'est pas ajouté lors de la définition. Il est simplement déclaré dans la classe.
  3. Les membres statiques de classe sont accessibles à l'aide du nom de classe :: membre statique ou membre object.static
  4. Les fonctions membres statiques n’ont pas de pointeur caché et ne peuvent accéder à aucun membre non statique.
  5. Les membres statiques sont également membres de la classe et sont limités par des qualificatifs d'accès public, protégé et privé.




4. Youyuan


Les amis offrent un moyen de briser l'encapsulation et offrent parfois une commodité. Cependant, les amis augmenteront le couplage et détruiront l'encapsulation, donc les amis ne devraient pas être utilisés plus d'une fois.

Les amis sont divisés en : fonctions d'amis et classes d'amis

4.1 Fonctions amis


Une fonction amie signifie que lorsqu'une fonction extérieure à la classe a besoin d'accéder à un membre privé de la classe, elle est accessible en déclarant cette fonction dans la classe comme fonction amie de la classe, par exemple :
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
  • Les fonctions amies peuvent accéder aux membres privés et protégés d'une classe, mais pas aux fonctions membres de la classe.
  • Les fonctions d'ami ne peuvent pas être modifiées avec const
  • Les fonctions Friend peuvent être déclarées n'importe où dans une définition de classe et ne sont pas limitées par des qualificatifs d'accès à la classe.
  • Une fonction peut être une fonction amie de plusieurs classes
  • Le principe d’appel des fonctions amies est le même que celui des fonctions ordinaires.

4.2 Classes d'amis


Lorsqu'une classe souhaite accéder aux membres privés d'une autre classe, elle peut déclarer cette classe comme amie dans la classe à laquelle il faut accéder, puis elle peut accéder à ses membres privés, par exemple :
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
  • Les relations amicales sont à sens unique et non commutatives. Par exemple, dans les classes Time et Date mentionnées ci-dessus, si vous déclarez la classe Date comme classe amie dans la classe Time, vous pouvez accéder directement aux variables membres privées de la classe Time dans la classe Date, mais vous souhaitez accéder aux variables membres privées de la classe Date dans la classe Time No.
  • La relation d’amitié ne peut pas être transitive. Si C est un ami de B et que B est un ami de A, cela ne peut pas signifier que C est un ami de A.




5. Classe interne


C++ prend en charge la création d'une autre classe à l'intérieur d'une classe, appelée classe interne. La classe interne est une classe indépendante. Elle n'appartient pas à la classe externe et les membres de la classe interne ne sont pas accessibles via les objets de la classe externe. . La classe externe n’a aucun accès supérieur à la classe interne.
Et la classe interne est naturellement amie de la classe externe, c'est-à-dire que la classe interne peut accéder aux membres privés de la classe externe.

caractéristique:

  1. Les classes internes peuvent être définies comme publiques, protégées ou privées dans les classes externes.
  2. Notez que les classes internes peuvent accéder directement aux membres statiques des classes externes sans nécessiter le nom d'objet/de classe de la classe externe.
  3. sizeof(external class)=classe externe, n'a rien à voir avec les classes internes.




6. Conclusion


Insérer la description de l'image ici

  Merci beaucoup d'avoir consulté mon article original.
  Cet article est principalement utilisé pour l'apprentissage personnel et le partage de connaissances. Le parcours d'apprentissage est long. S'il y a des erreurs, merci de me corriger.
  Si vous devez citer, veuillez indiquer l’adresse.