I think that the first const shows that you're returning a char* which will be const
That is correct. The what() member function returns a value of type const char *, which is a pointer to constant characters. This is exactly like a value returned from any other function. If you are not sure how to read type declarations involving pointers and const-specifiers, you should study up.
I think ... the second const is to ensure the object invoked (MyException) is not changed.
That is also correct. When a const specifier comes at the end of a member function's signature, it specifies that the member function operates on const instances of that type. In other words, this is legal:
const MyException myex;
std::cout << myex.what() << std::endl;
Whereas if const had been omitted from the what() function signature, the above code would have been illegal. myex would have had to have been non-const.
Generally, member functions that do not mutate the state of an object should be marked const to promote writing const-correct code.
Not sure on the throw().
This is a C++03-style exception specifier. The empty throw() is a guarantee that the function does not throw any exceptions. It is not a function call. The reason it is parenthesized is because it takes possible exceptions as arguments. For example, throw(int) means that the function might throw an exception of type int (which should never be thrown, but this is just an example).
The new C++11 style would be an annotation with noexcept. This is what you should generally prefer to use when writing modern C++ code, as others have
commented. Note that it doesn't use the parenthesized syntax anymore. This is because it was broadly agreed that dynamic exception specifications are useless, except in the very special case of indicating that a function does not throw at all.
Googling "exception specification c++" will return lots of relevant information.
Also is there a difference between using a struct and a class to create your own exception?
No, it does not matter. struct and class are identical in C++ except for the default access modifier. That is, by default, all members of a struct are public, whereas all members of a class are private by default.
In C++, the struct keyword really just defines a class. Now, semantically, I and others like to use struct for POD types and class for everything else, but this isn't something that is enforced by the language. You can use either one interchangeably (except on certain versions of MSVC, where it will issue warnings when it sees two different declarations of a class, one that uses struct and the other that uses class; this is, however, a nonsense warning and you can safely ignore or suppress it).