Torna indietro   Hardware Upgrade Forum > Software > Programmazione

Recensione vivo X300 Pro: è ancora lui il re della fotografia mobile, peccato per la batteria
Recensione vivo X300 Pro: è ancora lui il re della fotografia mobile, peccato per la batteria
vivo X300 Pro rappresenta un'evoluzione misurata della serie fotografica del produttore cinese, con un sistema di fotocamere migliorato, chipset Dimensity 9500 di ultima generazione e l'arrivo dell'interfaccia OriginOS 6 anche sui modelli internazionali. La scelta di limitare la batteria a 5.440mAh nel mercato europeo, rispetto ai 6.510mAh disponibili altrove, fa storcere un po' il naso
Lenovo Legion Go 2: Ryzen Z2 Extreme e OLED 8,8'' per spingere gli handheld gaming PC al massimo
Lenovo Legion Go 2: Ryzen Z2 Extreme e OLED 8,8'' per spingere gli handheld gaming PC al massimo
Lenovo Legion Go 2 è la nuova handheld PC gaming con processore AMD Ryzen Z2 Extreme (8 core Zen 5/5c, GPU RDNA 3.5 16 CU) e schermo OLED 8,8" 1920x1200 144Hz. È dotata anche di controller rimovibili TrueStrike con joystick Hall effect e una batteria da 74Wh. Rispetto al dispositivo che l'ha preceduta, migliora ergonomia e prestazioni a basse risoluzioni, ma pesa 920g e costa 1.299€ nella configurazione con 32GB RAM/1TB SSD e Z2 Extreme
AWS re:Invent 2025: inizia l'era dell'AI-as-a-Service con al centro gli agenti
AWS re:Invent 2025: inizia l'era dell'AI-as-a-Service con al centro gli agenti
A re:Invent 2025, AWS mostra un’evoluzione profonda della propria strategia: l’IA diventa una piattaforma di servizi sempre più pronta all’uso, con agenti e modelli preconfigurati che accelerano lo sviluppo, mentre il cloud resta la base imprescindibile per governare dati, complessità e lock-in in uno scenario sempre più orientato all’hybrid cloud
Tutti gli articoli Tutte le news

Vai al Forum
Rispondi
 
Strumenti
Old 10-09-2010, 13:50   #1
Opcode
Member
 
L'Avatar di Opcode
 
Iscritto dal: Jun 2010
Città: Asti
Messaggi: 85
[C++] Problema ereditando da una classe

Giorno a tutti,

per gestire varie eccezioni nella mia applicazione ho definito una classe Exception, così dichiarata:

Codice:
class Exception {
	protected:
		const char *_message;		///< Contains the error message.
		const char *what();			///< Simply returns the _message content.
	public:
		/// Base constructor.
		Exception(const char *msg): _message(msg) {};
		Exception() {};
		/**
		 * Shows the error exploiting the WINAPI MessageBox on Windows.
		 * On linux prints the message on the standard output.
		 */
		void show();
		/**
		 * Exactly like Exception::show but it causes the program termination.
		 * \warning This method causes the program termination!
		 */
		void fatal();
	};
e definita come segue:

Codice:
const char *Exception::what()
{
	return _message;
}

void Exception::show()
{
	std::string error(what());
	error.append("\n");
	error.append("Try reinstalling the application");
	MessageBoxA(NULL, error.c_str(), "An error has occurred!", MB_OK);
}

void Exception::fatal()
{
	std::string error(what());
	error.append("\n");
	error.append("Try reinstalling the application");
	MessageBoxA(NULL, error.c_str(), "A fatal error has occurred!", MB_OK);
	exit(EXIT_FAILURE);
}
Ho definito i metodi Exception::fatal ed Exception::show, sebbene la classe venga ereditata, per evitare di riscrivere in tutte le classi questi due metodi, qualora non ci fosse la necessità di usare qualcosa di diverso.

Ora veniamo al problema.
Ho dichiarato una classe che eredita la classe Exception (chiamata SDLException), in questa classe mi serve dichiarare anche nuovi metodi fatal ed exception perchè devono andare a recuperare il valore _message di SDLException, non quello della classe da cui ereditano, poichè non esistono overload del costruttore della classe Exception per accettare l'errore in questione.
Quindi diciamo, il principio è quello di ereditare dalla classe Exception per poter catturare l'eccezione in modo generico, ma poi chiamare il metodo "fatal" di SDLException, non quello di Exception.
Ecco la dichiarazione, seguita dalla definizione:
Codice:
class SDLException: public Exception {
	private:
		char *_message;
		const char *what();
	public:
		///	\param message the error message
		/// \param SDLError if true describes the SDL error
		SDLException(const char *message, bool SDLError);
		void fatal();
		void show();
	};
Codice:
SDLException::SDLException(const char *message, bool SDLError):
	Exception(message)
{
	string errorMsg(message);
	if (SDLError) {
		errorMsg.append("\n");
		errorMsg.append(SDL_GetError());
	}

	_message = new char[errorMsg.size()];
	errorMsg.copy(_message, errorMsg.size());
}

const char *SDLException::what()
{
	return _message;
}

void SDLException::show()
{
	std::string error(what());
	error.append("\n");
	error.append("Maybe reinstalling the game could fix this issue");
	MessageBoxA(NULL, error.c_str(), "An error has occurred!", MB_OK);
}

void SDLException::fatal()
{
	std::string error(what());
	error.append("\n");
	error.append("Maybe reinstalling the game could fix this issue");
	MessageBoxA(NULL, error.c_str(), "A fatal error has occurred!", MB_OK);
	exit(EXIT_FAILURE);
}
Qui i problemi sono due:
- Se non uso il costruttore Exception che accetta il messaggio come parametro (Exception::Exception(const char *), addirittura mi crasha il programma per eccezione non gestita.
- Se invece (come nella definizione precedente) passo il parametro Exception(message), l'eccezione viene gestita, ma qui:
Codice:
catch (Exception &ex) {
	ex.fatal();
	return 0;
}
Viene chiamato il metodo Exception::fatal() non il metodo SDLException::fatal().
Ricordo che la differenza tra i due è semplicemente il messaggio che vanno a prendere, SDLException prende un messaggio costruito anche con l'errore specifico della libreria esterna (SDLException::_message), mentre Exception::fatal() no (Exception::_message).

Come potrei risolvere (magari ambedue i problemi)?
Se ritenete inadatta la corrente implementazione, sono accette anche proposte per implementazioni differenti

Se non sono stato chiaro chiedete pure, rispondo appena possibile.
Grazie, buona giornata.
Opcode è offline   Rispondi citando il messaggio o parte di esso
Old 10-09-2010, 14:18   #2
tomminno
Senior Member
 
Iscritto dal: Oct 2005
Messaggi: 3306
La classe Exception non ha i metodi dichiarati come virtual.
Ma non capisco perchè mai ridichiarare _message (tra l'altro come char*) quando è già protected in Exception?
E ancora perchè non fai derivare Exception da std::exception?
Infine non è proprio bello che un'eccezione spari fuori un messagebox.
tomminno è offline   Rispondi citando il messaggio o parte di esso
Old 10-09-2010, 15:17   #3
Opcode
Member
 
L'Avatar di Opcode
 
Iscritto dal: Jun 2010
Città: Asti
Messaggi: 85
Anzitutto grazie della risposta. Mi hai aiutato a fixare il problema.
Quote:
Originariamente inviato da tomminno Guarda i messaggi
La classe Exception non ha i metodi dichiarati come virtual.
Questo mi ha permesso di utilizzare i metodi della classe figlio, ci avevo pensato già alla virtual ma non ero sicuro di poter dichiarare un metodo virtuale e poi poterlo definire (per altro colpa mia che mi son fatto venire il dubbio, dopo averlo già fatto).
Quote:
Ma non capisco perchè mai ridichiarare _message (tra l'altro come char*) quando è già protected in Exception?
Anche qui, ti ringrazio, avevo fatto la modifica proprio per poterci lavorare ma mi ero dimenticato di usare quello. Probabilmente non devo lavorarci sopra quando sono stanco
Quote:
E ancora perchè non fai derivare Exception da std::exception?
Sinceramente?
Non vedo cosa mi possa offrire in più il derivare da std::exception la mia classe Exception. Sicuramente mi sbaglio, magari potrai illuminarmi. Non mi costa nulla farla derivare da quella eccezione.
Quote:
Infine non è proprio bello che un'eccezione spari fuori un messagebox.
Queste eccezioni sono per un programma con interfaccia grafica, e se qualcosa và storto bisogna mostrarlo all'utente e pensavo di farlo tramite una MessageBox, tutto qui. Si capisce che se fosse una applicazione diversa, non mi verrebbe mai in mente di usare la MessageBox. Hai qualche soluzione alternativa da proporre per fare questo?


Grazie ancora.
Opcode è offline   Rispondi citando il messaggio o parte di esso
Old 10-09-2010, 15:55   #4
tomminno
Senior Member
 
Iscritto dal: Oct 2005
Messaggi: 3306
Quote:
Originariamente inviato da Opcode Guarda i messaggi
Sinceramente?
Non vedo cosa mi possa offrire in più il derivare da std::exception la mia classe Exception. Sicuramente mi sbaglio, magari potrai illuminarmi. Non mi costa nulla farla derivare da quella eccezione.
Il fatto di non dover gestire _message e what()?
Infine, giusto prendendo spunto da i linguaggi che sono venuti dopo, male non fa derivare le eccezioni da quelle della libreria standard, qualcuno potrebbe avere nel codice un catch(const std::exception & ex) e riuscre a catturare la tua eccezione riuscendo a leggerne il messaggio d'errore.

Quote:
Queste eccezioni sono per un programma con interfaccia grafica, e se qualcosa và storto bisogna mostrarlo all'utente e pensavo di farlo tramite una MessageBox, tutto qui. Si capisce che se fosse una applicazione diversa, non mi verrebbe mai in mente di usare la MessageBox. Hai qualche soluzione alternativa da proporre per fare questo?


Grazie ancora.
Più che altro a livello di separazione delle responsabilità proprie della programmazione ad oggetti e di riusabilità del codice.
Se volessi utilizzare le tue classi per gestire eccezioni interne non necessariamente da mostrare all'utente?
Infine, forse nell'immediato più importante di tutte le pippe mentali riguardo alla corretta scrittura del codice, non passando l'HWND del parent al messagebox (che nel contesto dell'eccezione ovviamente non hai) l'utente potrebbe non accorgersi del messagebox in quanto potrebbe rimanere nascosto dall'interfaccia del programma, non risultando quindi bloccante. In tal caso l'utente continuerebbe ad utilizzare il programma in condizioni potenzialmente instabili.
tomminno è offline   Rispondi citando il messaggio o parte di esso
Old 10-09-2010, 16:29   #5
Opcode
Member
 
L'Avatar di Opcode
 
Iscritto dal: Jun 2010
Città: Asti
Messaggi: 85
Quote:
Originariamente inviato da tomminno Guarda i messaggi
Il fatto di non dover gestire _message e what()?
Perdona la mia ignoranza, se sbaglio correggimi, ma la classe std::exception definisce exception::what() come:
Codice:
  virtual const char* what() const throw();
Quindi dovrei comunque farne la mia implementazione, e stando alla documentazione:
Codice:
class exception {
public:
  exception () throw();
  exception (const exception&) throw();
  exception& operator= (const exception&) throw();
  virtual ~exception() throw();
  virtual const char* what() const throw();
}
Non ha un membro _message per salvare l'errore (giustamente è la base exception class), quindi la sola motivazione che mi sembra reggere è:
Quote:
Infine, giusto prendendo spunto da i linguaggi che sono venuti dopo, male non fa derivare le eccezioni da quelle della libreria standard, qualcuno potrebbe avere nel codice un catch(const std::exception & ex) e riuscre a catturare la tua eccezione riuscendo a leggerne il messaggio d'errore.
Quote:
Più che altro a livello di separazione delle responsabilità proprie della programmazione ad oggetti e di riusabilità del codice.
Se volessi utilizzare le tue classi per gestire eccezioni interne non necessariamente da mostrare all'utente?
Basterebbe catturare l'eccezione e non chiamare uno dei metodi show() o fatal()... probabilmente dovrei rendere accessibile il metodo what per ottenere l'errore in modo non intrusivo.
Quote:
Infine, forse nell'immediato più importante di tutte le pippe mentali riguardo alla corretta scrittura del codice, non passando l'HWND del parent al messagebox (che nel contesto dell'eccezione ovviamente non hai) l'utente potrebbe non accorgersi del messagebox in quanto potrebbe rimanere nascosto dall'interfaccia del programma, non risultando quindi bloccante. In tal caso l'utente continuerebbe ad utilizzare il programma in condizioni potenzialmente instabili.
A questo non ci avevo pensato, ed effettivamente non hai torto, sui test che ho effettuato il popup della MessageBox ha sempre portato quest'ultima in primo piano.
Opcode è offline   Rispondi citando il messaggio o parte di esso
Old 10-09-2010, 17:46   #6
tomminno
Senior Member
 
Iscritto dal: Oct 2005
Messaggi: 3306
Quote:
Originariamente inviato da Opcode Guarda i messaggi
Perdona la mia ignoranza, se sbaglio correggimi, ma la classe std::exception definisce exception::what() come:
Codice:
  virtual const char* what() const throw();
Quindi dovrei comunque farne la mia implementazione, e stando alla documentazione:
Codice:
class exception {
public:
  exception () throw();
  exception (const exception&) throw();
  exception& operator= (const exception&) throw();
  virtual ~exception() throw();
  virtual const char* what() const throw();
}
Non ha un membro _message per salvare l'errore (giustamente è la base exception class), quindi la sola motivazione che mi sembra reggere è:
In realtà potresti riuscire a comporre il messaggio d'errore nel costruttore, io ad esempio ho costruito una classe Win32Exception che compone in un metodo statico il messaggio d'errore ricavato da FormatMessageA in modo da avere un'eccezione sollevata in caso di una chiamata Win32 fallita.
Nel mio caso non è stato necessario avere nessun campo stringa aggiuntivo e tutta l'informazione è recuperabile tramite il what di exception. Magari non è esattamente il tuo caso, in ogni caso basta una variabile stringa di appoggio e ridefinire what() nella tua classe.
Io comunque ti consiglio di abbandonare l'utilizzo di stringhe C e utilizzare solamente std::string troppo più comode e soprattutto molto più sicure da utilizzare.

Quote:
Basterebbe catturare l'eccezione e non chiamare uno dei metodi show() o fatal()... probabilmente dovrei rendere accessibile il metodo what per ottenere l'errore in modo non intrusivo.
Stai legando indissolubilmente tutti gli utilizzatori della tua Exception al funzionamento interno della classe. In caso di refactoring del codice qualcosa potrebbe smettere di funzionare.

Quote:
A questo non ci avevo pensato, ed effettivamente non hai torto, sui test che ho effettuato il popup della MessageBox ha sempre portato quest'ultima in primo piano.
Ad esempio se l'utente ottiene un'eccezione che causa l'invocazione del metodo fatal, ma prima che questo venga invocato esegue altre azioni sulla GUI è molto probabile che il messagebox rimanga poi in secondo piano.
tomminno è offline   Rispondi citando il messaggio o parte di esso
Old 11-09-2010, 22:26   #7
Opcode
Member
 
L'Avatar di Opcode
 
Iscritto dal: Jun 2010
Città: Asti
Messaggi: 85
Quote:
Originariamente inviato da tomminno Guarda i messaggi
In realtà potresti riuscire a comporre il messaggio d'errore nel costruttore, io ad esempio ho costruito una classe Win32Exception che compone in un metodo statico il messaggio d'errore ricavato da FormatMessageA in modo da avere un'eccezione sollevata in caso di una chiamata Win32 fallita.
Nel mio caso non è stato necessario avere nessun campo stringa aggiuntivo e tutta l'informazione è recuperabile tramite il what di exception. Magari non è esattamente il tuo caso, in ogni caso basta una variabile stringa di appoggio e ridefinire what() nella tua classe.
Io comunque ti consiglio di abbandonare l'utilizzo di stringhe C e utilizzare solamente std::string troppo più comode e soprattutto molto più sicure da utilizzare.
Seguirò i tuoi consigli. Ho già implementato la nuova classe Exception derivando da std::exception.
Riguardo l'uso delle std::string adotterò anche questo consiglio. Per ora l'unico problema, come da un più vecchio topic, è la persistenza del messaggio d'errore quando la std::string và out-of-scope (con un throw). Non mi và di utilizzare librerie esterne solo per aggirare questo problema.

Quote:
Stai legando indissolubilmente tutti gli utilizzatori della tua Exception al funzionamento interno della classe. In caso di refactoring del codice qualcosa potrebbe smettere di funzionare.
Non saprei come altro fare, cioè posso fare il solo metodo che restituisce sotto forma di std::string l'errore testuale, e tutte le altre informazioni utili nel contesto di gestione dell'eccezione, ma poi toccherebbe al programmatore finale, chiamare la MessageBoxA. Quello che dici non è affatto sbagliato, anzi, però potrebbe essere snervante visto che le eccezioni derivate da Exception saranno tutte da mostrare all'utente finale.
Quote:
Ad esempio se l'utente ottiene un'eccezione che causa l'invocazione del metodo fatal, ma prima che questo venga invocato esegue altre azioni sulla GUI è molto probabile che il messagebox rimanga poi in secondo piano.
Chiarissimo.

Grazie ancora, mi stai aiutando ad entrare ulteriormente nell'ottica C++.
Opcode è offline   Rispondi citando il messaggio o parte di esso
 Rispondi


Recensione vivo X300 Pro: è ancora lui il re della fotografia mobile, peccato per la batteria Recensione vivo X300 Pro: è ancora lui il...
Lenovo Legion Go 2: Ryzen Z2 Extreme e OLED 8,8'' per spingere gli handheld gaming PC al massimo Lenovo Legion Go 2: Ryzen Z2 Extreme e OLED 8,8'...
AWS re:Invent 2025: inizia l'era dell'AI-as-a-Service con al centro gli agenti AWS re:Invent 2025: inizia l'era dell'AI-as-a-Se...
Cos'è la bolla dell'IA e perché se ne parla Cos'è la bolla dell'IA e perché se...
BOOX Palma 2 Pro in prova: l'e-reader diventa a colori, e davvero tascabile BOOX Palma 2 Pro in prova: l'e-reader diventa a ...
Toyota usa giochi e premi per spingere i...
HarmonyOS ha raggiunto la soglia di sopr...
Le offerte Amazon più convenienti...
Un gruppo di ladri ha usato Google Maps ...
Apple non si fida di Samsung per la real...
Windows 11: un nuovo driver nativo mette...
Vi hanno regalato buoni Amazon? Intanto ...
Via acari, polvere e sporco da materassi...
Cuffie Beats in super offerta su Amazon,...
Xbox Cloud Gaming arriva su Amazon Fire ...
Un blackout a San Francisco manda in til...
Windows 11 è diventato più...
Apple cambia strategia a causa della cri...
007 First Light: uscita rimandata di due...
Samsung Galaxy A37 e A57: il comparto fo...
Chromium
GPU-Z
OCCT
LibreOffice Portable
Opera One Portable
Opera One 106
CCleaner Portable
CCleaner Standard
Cpu-Z
Driver NVIDIA GeForce 546.65 WHQL
SmartFTP
Trillian
Google Chrome Portable
Google Chrome 120
VirtualBox
Tutti gli articoli Tutte le news Tutti i download

Strumenti

Regole
Non Puoi aprire nuove discussioni
Non Puoi rispondere ai messaggi
Non Puoi allegare file
Non Puoi modificare i tuoi messaggi

Il codice vB è On
Le Faccine sono On
Il codice [IMG] è On
Il codice HTML è Off
Vai al Forum


Tutti gli orari sono GMT +1. Ora sono le: 21:14.


Powered by vBulletin® Version 3.6.4
Copyright ©2000 - 2025, Jelsoft Enterprises Ltd.
Served by www3v