A doubt about C++ methods override

Started by
7 comments, last by Zahlman 14 years, 11 months ago
Hello guys and gals. This is my first topic, so don't mock me X-D. I'm relatively new to C++, but I've got some notions on programming from other languagens (Object Pascal/Delphi, Java). So, here is what I'm trying do do: I've got two exception classes, called CmyException and CmyFileException. The last one inherits from CmyException, and this one from stl::exceptino. Ok, so far so good. The problem lies in the virtual method "checkMessage()". In the following code:

#include <string>
#include <iostream>
#include "myFileException.h"

using std::string;
using std::cout;
using std::endl;

int main( int argc, char *args[] )
{
	try
	{
		throw CmyFileException( CmyFileException::excNoLoadedFile );
	}
	catch( exception &e )
	{
		cout << e.what() << endl;
	}
}

when I call "e.what()", It actually gets the CmyException string ("Default Message"), instead of the CmyFileException, from the virtual method "checkMessage()". Why does this happen? Shouldn't it try to get checkMessage from CmyFileException before CmyException? BTW: I tryed without the virtual method, and I've had the same problem... Here are the other files: myException.h

#ifndef INC_MYEXCEPTION_H
#define INC_MYEXCEPTION_H

#include <exception>

using std::exception;

class CmyException : public exception
{
	public:
		typedef enum typeExcepts
		{
			excUnknownError = -1,
			excNotImplemented = -2,
			excCouldNotInitialize = -3
		};

		//Constructor/Destructor
		CmyException( int option ) throw();
		~CmyException( void ) throw();

		virtual const char* what( void ) const throw();
		virtual const int code( void ) const throw();

	protected:
		int id;
		char* message;

		virtual void checkMessage( void ) throw();
	private:

};

#endif //INC_MYEXCEPTION_H

myException.cpp

#include "myException.h"

CmyException::CmyException( int option ) throw()
{
	this->id = option;
	this->checkMessage();
}

CmyException::~CmyException( void ) throw()
{
	/* ... */
}

void CmyException::checkMessage( void ) throw()
{
	switch( this->id )
	{
		case excUnknownError :
			this->message = "Unknown error!";
			break;

		case excNotImplemented :
			this->message = "Not implemented yet!";
			break;

		case excCouldNotInitialize :
			this->message = "Could not initialize object";
			break;

		default :
			this->message = "Default Message!";
			break;
	}
}

const char *CmyException::what(void) const throw()
{
	return this->message;
}

const int CmyException::code( void ) const throw()
{
	return this->id;
}

myFileException.h

#ifndef INC_MYFILEEXCEPTION_H
#define INC_MYFILEEXCEPTION_H

#include "myException.h"

class CmyFileException : public CmyException
{
	public:
		typedef enum typeExcepts
		{
			excNoLoadedFile = 0
		};

		CmyFileException( int option ) throw();
		~CmyFileException( void ) throw();
	protected:
		virtual void checkMessage( void ) throw();
	private:

};

#endif //INC_MYFILEEXCEPTION_H

myFileException.cpp

#include "myFileException.h"
#include "myException.h"

CmyFileException::CmyFileException( int option ) throw() :
	CmyException( option )
{
	/* ... */
}
CmyFileException::~CmyFileException( void ) throw()
{
	/* ... */
}

void CmyFileException::checkMessage( void ) throw()
{
	switch( this->id )
	{
		case excNoLoadedFile :
			this->message = "Could not load the file";
			break;

		default :
			CmyException::checkMessage(); //Don't know if this is correct...
                        //I'm trying to do something like a "inherited;" command from Delphi here...
			break;
	}
}

Oh, and since i'm asking about c++, in this piece of code:

CmyFileException::CmyFileException( int option ) throw() :
	CmyException( option )
{
	/* ... */
}

Is there another way to call the CmyException contructor? I mean, a different sintax, or something? (Just for curiosity) Thansks in advance :D
Advertisement
Based on a quick look through your code, I'm thinking these links might be of help:

Link 1
Link 2

Again, I only glanced through the code, so I could be off base here.
That's exactly the problem.

Further, the use of (void) to denote no arguments is a C convention. In C++ () is proper.

For the second question, no. That is the only syntax. Initializer lists were created specifically to solve the problem of calling parent constructors.
Quote:Original post by jyk
Based on a quick look through your code, I'm thinking these links might be of help:

Link 1
Link 2

Again, I only glanced through the code, so I could be off base here.


Bull's eye!

Thanks :D
Quote:Original post by Deyja
That's exactly the problem.

Further, the use of (void) to denote no arguments is a C convention. In C++ () is proper.

For the second question, no. That is the only syntax. Initializer lists were created specifically to solve the problem of calling parent constructors.


Thanks about the construtor answer ;D.

Oh, and about the (void), I had no ideia :P. Thanks for the info. I've already changed it all over the code.
To fix the problem, don't set a 'message' member at all; instead, use the current checkMessage() logic to implement what(). There's nothing that requires you to return a stored value; it's a const char*, after all.

Also, what's a Cmy? (If prefixing class names with C were a good idea, don't you think the standard library would have done it? In *any* language?)
Quote:Original post by Zahlman
To fix the problem, don't set a 'message' member at all; instead, use the current checkMessage() logic to implement what(). There's nothing that requires you to return a stored value; it's a const char*, after all.


Well, that's 'cause my method inherits from std::exception and there is a const at the end of the method declaration "what" that, as far as I know, doesn't allow me to change any value (a read only method). And by doing it that way, what() will recalculate the value of id every time it's called. (Note: I can be wrong about what I'm saying here, since I'm no C++ expert.)

Quote:Original post by Zahlman
Also, what's a Cmy? (If prefixing class names with C were a good idea, don't you think the standard library would have done it? In *any* language?)


Well, Java prefix some of it's classes with an "J" at the front of the name :P, like JLabel or JFrame.

And about every single example that I meet on the internet that refer to C++ classes, they contain a C at the beggining of the name. :P

But no reason at all. Just esthetic.
Quote:Original post by Nalpam
Quote:Original post by Zahlman
To fix the problem, don't set a 'message' member at all; instead, use the current checkMessage() logic to implement what(). There's nothing that requires you to return a stored value; it's a const char*, after all.


Well, that's 'cause my method inherits from std::exception and there is a const at the end of the method declaration "what" that, as far as I know, doesn't allow me to change any value (a read only method). And by doing it that way, what() will recalculate the value of id every time it's called. (Note: I can be wrong about what I'm saying here, since I'm no C++ expert.)

His point is: you can implement what() like this:
const char *CmyException::what(void) const throw(){	switch( this->id )	{		case excUnknownError: return "Unknown error!";		case excNotImplemented: return "Not implemented yet!";		case excCouldNotInitialize: return "Could not initialize object";		default :			// You may want to use "assert" here.			// Or in the constructor.			return "Default Message!";	}}

This way you don't need to have a "message" member.

In any case, its bad style to point a non-const char pointer at a string literal. Its allowed for legacy reasons, but its not a good idea.

Quote:Original post by Zahlman
Well, Java prefix some of it's classes with an "J" at the front of the name :P, like JLabel or JFrame.

That is because they already had classes called Label and Frame and they wanted to differentiate between the new and the old classes. But since they reside in different packages, it seems like a fairly odd decision.
Quote:
And about every single example that I meet on the internet that refer to C++ classes, they contain a C at the beggining of the name. :P

Yes, but that doesn't make it a good practise. In almost every case, if the code is properly written it will be clear which names are types and which are identifiers. A simple one is: types are always begin with an uppercase letter, and identifiers with a lowercase one.
Quote:
But no reason at all.

If there is no reason, then logically you should omit it. After all, its more work to include it that it is to not type that extraneous "C".
Quote:Original post by Nalpam
Well, that's 'cause my method inherits from std::exception and there is a const at the end of the method declaration "what" that, as far as I know, doesn't allow me to change any value (a read only method).


Doesn't allow you to change any members of the instance. But performing the calculation won't change anything.

Quote:And by doing it that way, what() will recalculate the value of id every time it's called.


Yes, but the "recalculation" is just looking up a const char* (which is already stored in the program) that corresponds to the ID. It doesn't copy any text; it just returns a pointer to existing (un-modifiable) text. This is very fast. Much, much faster than actually throwing the exception was.

Quote:And about every single example that I meet on the internet that refer to C++ classes, they contain a C at the beggining of the name. :P


The unfortunate thing about C++ is that you really can't learn it from examples on the internet. There are far more people out there who repeat what they were taught instead of actually thinking.

This topic is closed to new replies.

Advertisement