Point 1
const char* IllegalArgumentException::what() { return s.c_str(); }
is declared incorrectly if declared inside a class
or struct
. Since the declaration is being made inside the IllegalArgumentException
class, IllegalArgumentException::
is implied and messes with the compiler because the compiler now thinks you are declaring something else. You want
const char* what() { return s.c_str(); }
In addition, the { return s.c_str(); }
portion implements the function, so there is no need to implement it in the cpp file.
Point 2
Everything in a struct
is public
unless declared following the private
keyword. This is the opposite of a class
where everything is private
unless stated otherwise. A class
and a struct
are pretty much identical other than the difference on default access.
Point 3
In C++ you can declare access level of members in blocks. There is no need to declare the access level of members one at a time.
struct IllegalArgumentException : public std::exception
{
// these are all public by default in a struct
IllegalArgumentException(std::string ss);
~IllegalArgumentException();
const char* IllegalArgumentException::what() { return s.c_str(); }
private: // everything after this is private
std::string s;
int example;
};
or
class IllegalArgumentException : public std::exception
{
public: // these are all private by default in a class and need to be public
IllegalArgumentException(std::string ss);
~IllegalArgumentException();
const char* IllegalArgumentException::what() { return s.c_str(); }
private: // switch back to private
std::string s;
int example;
};
or
class IllegalArgumentException : public std::exception
{
// these are all private by default in a class
std::string s;
int example;
public: // everything after this is public
IllegalArgumentException(std::string ss);
~IllegalArgumentException();
const char* IllegalArgumentException::what() { return s.c_str(); }
};
Point 4
IllegalArgumentException::~IllegalArgumentException() {}
doesn't do anything. It doesn't need to do anything so the Rule of Zero recommends against having a destructor at all. The compiler will create it for you. If you don't have to write it, don't write it because code that doesn't exist has no bugs.
class IllegalArgumentException : public std::exception
{
// these are all private by default
std::string s;
int example;
public: // everything after this is public
IllegalArgumentException(std::string ss);
const char* IllegalArgumentException::what() { return s.c_str(); }
};
Point 5
Stealing from KerrekSB here because it's a point that OP had another question on. Use Include Guards
Include guards prevent a header from being included multiple times in the same translation unit. This is a problem because of bloat and the possibility of the same thing being defined or declared more than once leading to confusion about which is the real one.
A simple header guard:
#ifndef ILLEGALARGUMENTEXCEPTION_H // if we've never seen ILLEGALARGUMENTEXCEPTION_H
// before, do the following
#define ILLEGALARGUMENTEXCEPTION_H // OK we've seen it now!
// all subsequent includes of IllegalArgumentException.h will have seen
// ILLEGALARGUMENTEXCEPTION_H and fail the ifndef, skipping everything
// until it finds the closing #endif
#include <string>
#include <exception>
class IllegalArgumentException : public std::exception
{
// these are all private by default
std::string s;
int example;
public: // everything after this is public
IllegalArgumentException(std::string ss);
const char* IllegalArgumentException::what() { return s.c_str(); }
};
#endif // end of Include Guard
You may also use #pragma once
, but be warned that #pragma
means non-standard compiler extension. once
may not exist for your compiler and if it doesn't, the compiler is allowed to skip the instruction without telling you!
There are many reasons why once
is not in the standard, most important is it has unresolved fail cases. Use it with caution.