Liste di inizializzazione dei costruttori
Fa parte della sezione Programmazione orientata agli oggetti del percorso C++ di Coddy. Lezione 22 di 104.
Hai già visto la sintassi con i due punti in lezioni precedenti, come Player(std::string n, int h) : name(n), health(h) {}. Si chiama lista di inizializzazione dei membri ed è il modo preferito per inizializzare i membri in C++.
L’elenco di inizializzazione compare dopo l’elenco dei parametri del costruttore, iniziando con due punti. Ogni membro viene inizializzato direttamente con il proprio valore, separato da virgole:
class Rectangle {
int width;
int height;
const int id;
int& reference;
public:
Rectangle(int w, int h, int i, int& r)
: width(w), height(h), id(i), reference(r) {
// Corpo del costruttore (può essere vuoto)
}
};Perché usare le liste di inizializzazione invece dell'assegnazione nel corpo del costruttore? Con l'assegnazione, i membri vengono prima costruiti con i valori predefiniti e poi ricevono i nuovi valori. Con le liste di inizializzazione, i membri vengono costruiti direttamente con i valori corretti: è più efficiente e talvolta necessario.
Alcuni membri devono essere inizializzati utilizzando la lista:
- membri
const- non possono essere assegnati dopo la costruzione
- Membri di riferimento: devono essere associati durante l'inizializzazione
- Membri senza costruttori predefiniti
class Player {
const int maxHealth; // È necessario usare la lista di inizializzazione
std::string name;
public:
// Questo funziona
Player(int max, std::string n) : maxHealth(max), name(n) {}
// Questo NON verrebbe compilato:
// Player(int max) { maxHealth = max; } // Errore!
};I membri vengono inizializzati nell'ordine in cui sono dichiarati nella classe, non nell'ordine dell'elenco degli inizializzatori. Scrivi sempre l'elenco degli inizializzatori nell'ordine di dichiarazione per evitare confusione.
Sfida
FacileCostruiamo un sistema di configurazione per un motore di gioco che dimostri quando e perché le liste di inizializzazione dei membri sono essenziali. Creerai una classe GameConfig con membri che MUST essere inizializzati usando la sintassi delle liste di inizializzazione.
Creerai due file per organizzare il codice:
GameConfig.h: definisci una classeGameConfigche memorizza le impostazioni del gioco. La classe deve avere:- Una
const std::string gameName: il titolo del gioco, che non può essere modificato dopo la creazione - Una
const int maxPlayers: il numero massimo di giocatori, fissato al momento della costruzione - Una
int& difficultyRef: un riferimento a un'impostazione di difficoltà esterna - Un
int screenWidthe unint screenHeight: membri normali per le impostazioni di visualizzazione - Un costruttore che accetta tutti i parametri necessari e inizializza EVERY membro usando la lista di inizializzazione. La lista di inizializzazione deve seguire l'ordine in cui i membri sono dichiarati nella classe
- Un metodo
display()che stampa la configurazione in questo formato:Game: <gameName> Max Players: <maxPlayers> Difficulty: <difficultyRef value> Resolution: <screenWidth>x<screenHeight>
- Una
main.cpp: leggi i valori di configurazione dall'input e crea un oggetto GameConfig. Dovrai:- Leggere dall'input il nome del gioco (string), il numero massimo di giocatori (int), la difficoltà (int), la larghezza (int) e l'altezza (int): ciascuno su una riga separata
- Creare una variabile locale
intper la difficoltà a cui farà riferimento la configurazione - Creare un oggetto
GameConfigusando il costruttore con lista di inizializzazione - Chiamare
display()per mostrare la configurazione iniziale - Modificare direttamente la variabile della difficoltà (moltiplicarla per 2)
- Stampare
"After difficulty change:" - Chiamare di nuovo
display()per mostrare che il riferimento riflette il valore aggiornato
Questa sfida evidenzia perché le liste di inizializzazione sono importanti: i membri const e il membro riferimento non possono essere assegnati nel corpo del costruttore. Devono essere inizializzati nella lista. Il membro riferimento dimostra anche come le modifiche alla variabile originale si riflettano attraverso l'oggetto di configurazione.
Includi il file header in main.cpp usando #include "GameConfig.h".
Provalo tu
#include <iostream>
#include <string>
#include "GameConfig.h"
using namespace std;
int main() {
// Leggi i valori di input
string gameName;
getline(cin, gameName);
int maxPlayers;
cin >> maxPlayers;
int difficulty;
cin >> difficulty;
int width;
cin >> width;
int height;
cin >> height;
// TODO: Crea un oggetto GameConfig usando il costruttore con lista di inizializzazione
// Il costruttore deve ricevere: gameName, maxPlayers, difficulty (per riferimento), width, height
// TODO: Chiama display() per mostrare la configurazione iniziale
// TODO: Modifica direttamente la variabile difficulty (moltiplicala per 2)
// TODO: Stampa "After difficulty change:"
// TODO: Chiama di nuovo display() per mostrare la configurazione aggiornata
return 0;
}
Questa lezione include un breve quiz. Inizia la lezione per rispondere e tenere traccia dei tuoi progressi.
Tutte le lezioni di Programmazione orientata agli oggetti
1Fondamenti della programmazione orientata agli oggetti
File esterniBuild e compilazione in C++File header e file sorgenteNamespace e ambitoIntroduzione alla programmazione orientata agli oggetti in C++Classi e oggetti a confrontoIl puntatore 'this'Metodi (funzioni membro)Attributi (membri dati)Fondamenti di costruttori e distruttoriRiepilogo - Calcolatrice semplice4Proprietà delle classi
Membri di istanza e staticiGetter e setterFunzioni membro constParola chiave mutableMetodi e variabili staticiFunzioni e classi friendRiepilogo - Gestore di conti bancari7Ereditarietà
Ereditarietà di baseLivelli di accesso nell’ereditarietàOrdine di chiamata di costruttori e distruttoriRidefinizione dei metodiFunzioni virtuali e VTableEreditarietà multiplaEreditarietà virtualeRiepilogo - Gerarchia dei dipendenti2Gestione della memoria
Memoria Stack vs HeapPuntatori e riferimentiMemoria dinamica (new/delete)Puntatori intelligenti in C++RAII in C++Riepilogo - Gestore di array dinamico5Incapsulamento
Specificatori di accesso in C++Specificatori di accesso in dettaglioOccultamento delle informazioniStruct vs classClassi annidate e interneRiepilogo - Sistema di registrazione degli studenti8Polimorfismo
Polimorfismo a compile time e a runtimeOverload delle funzioniFunzioni virtuali: ripassoFunzioni virtuali pureClassi astratteProgettazione delle interfacce in C++Dynamic casting e RTTIRipasso: calcolatrice di forme11Concetti avanzati di OOP
Composizione vs ereditarietàMixin tramite CRTPIdiom PimplType ErasureEnum class e tipizzazione forteGestione delle eccezioni in OOPGerarchie personalizzate di eccezioni14Pattern di progettazione - Parte 2
Pattern CommandPattern AdapterPattern DecoratorPattern Template MethodPattern StatePattern CompositeRAII come pattern3Costruttori e distruttori
Costruttore predefinitoCostruttore con parametriCostruttore di copiaCostruttore di spostamentoListe di inizializzazione dei costruttoriCostruttori delegantiApprofondimento sui distruttoriRegola del Tre / Cinque / ZeroRipasso - classe String6Sovraccarico degli operatori
Introduzione al sovraccarico degli operatoriSovraccarico degli operatori aritmeticiSovraccarico degli operatori di confrontoOperatori di flussoSovraccarico dell'operatore di assegnazioneSovraccarico degli operatori [] e ()Operatori di conversione di tipoRipasso - Classe Matrix9Template
Template di funzioneTemplate di classeSpecializzazione dei templateTemplate variadiciBasi di SFINAE e dei trait di tipoRiepilogo - Contenitore genericoEsercitati da solo: Compilatore C++ online