0

I have the following code:

#include <exception>

class Exception : public std::exception {
private:
    const char* MESSAGE = "Exception"

public:
    inline virtual const char* what() const throw() {
        return this->MESSAGE;
    }
};

class ShoulderROMException : public Exception {
private:
    typedef Exception super;
    const char* MESSAGE = "ShoulderROM exception";

protected:
    static const int MAX_MESSAGE_LENGTH = 200;
    mutable char composedMessage[ShoulderROMException::MAX_MESSAGE_LENGTH];

public:
    virtual const char* what() const throw() {
        strcpy(this->composedMessage, super::what());
        strcat(this->composedMessage, " -> ");
        strcat(this->composedMessage, this->MESSAGE);
        return this->composedMessage;
    }
};

class KinectInitFailedException : public ShoulderROMException {
private:
    typedef ShoulderROMException super;
    const char* MESSAGE = "Kinect initialization failed."

public:
    virtual const char* what() const throw() {
        strcpy(this->composedMessage, super::what());
        strcat(this->composedMessage, " -> ");
        strcat(this->composedMessage, this->MESSAGE);
        return this->composedMessage;
    }
};

This produces log entries looking like this: Exception -> ShoulderROM exception -> Kinect initialization failed. This is exactly what I want but I would like to avoid the obvious code duplication and can't seem to find a(n elegant) way to do so.

Would be really nice, if someone could help me out here. :)

Best regards, Lilo

Lilo
  • 341
  • 2
  • 14
  • Calling `what` several times will currently fail in strange ways. Have you considered using nested exceptions? Are you using character arrays instead of strings because of exception safety vs memory allocation? – dyp Dec 09 '15 at 11:22
  • Have you already considered [boost.exceptions](http://www.boost.org/doc/libs/1_59_0/libs/exception/doc/tutorial_diagnostic_information.html)? – dyp Dec 09 '15 at 13:14
  • Yes i considered boost and several project related reasons doens't allow me to use it. Plus I am not a huge friend of boost. I am not using strings because `std::exception` forces the type `char*`. – Lilo Dec 09 '15 at 13:46
  • I don't quite understand what you mean with "`std::exception` forces the type `char*`". The only relation between `std::exception` and `char*` I know of is `std::exception::what`, which returns a `char const*`. But it is possible to store a `std::string` data member inside a `std::exception` and use `std::string::c_str` to return a `char const*` from `std::exception::what`. The issue with `std::string` is dynamic memory allocation, but this is not necessarily a concern in practice, and can sometimes be avoided by using `std::runtime_error` instead. – dyp Dec 09 '15 at 15:08

2 Answers2

1

Implement it through a common class. I would rewrite your code like this:

class Exception : public std::exception {
    static const char* MESSAGE = "Exception"
    static const int MAX_MESSAGE_LENGTH = 200;
    mutable char composedMessage[MAX_MESSAGE_LENGTH];

public:
    virtual const char* name() const throw() {
        return MESSAGE;
    }

    virtual const char* what() const throw() {
        strcpy(this->composedMessage, name());
        strcat(this->composedMessage, " -> ");
        strcat(this->composedMessage, this->MESSAGE);
        return this->composedMessage;
    }
};

class ShoulderROMException : public Exception {
    static const char* MESSAGE = "ShoulderROM exception";
public:    
    virtual const char* name() const throw() {
        return MESSAGE;
    }
};

class KinectInitFailedException : public ShoulderROMException {
    static const char* MESSAGE = "Kinect initialization failed."
public:
    virtual const char* name() const throw() {
        return MESSAGE;
    }
};

If you dont want so much implementation in the Exception class, add another from which both ShoulderROMException and KinectInitFailedExceptionwill inherit.

There is other issues with your code: The MESSAGE members should be static, and your way to deal with strings is not very C++ish. I would also add that inlining a virtual function does not make any sense.

Jean-Bernard Jansen
  • 7,544
  • 2
  • 20
  • 17
  • Thanks for the suggestion, I like it. Will test it in the next minutes. That `MESSAGE` should be static is completely right, missed that one. Why does inlining a virtual function not make sense? And what do you mean with the string handling? If you suggest, that I should use `std::string` then I have to point out that `char*` is forced by `std::exception`. – Lilo Dec 09 '15 at 12:40
  • Your suggestion solves the problem for all classes directly derived from `Exception` but not for classes that are derivatives from subclasses from `Exception`. The log only gets the message from `Exception` and the sub subclass from `Exception`. So in this example the log would say `Exception -> Kinect initialization failed.` instead of `Exception -> ShoulderROM exception -> Kinect initialization failed.`. Is there a way to achieve such recursivity without the mentioned code duplication? – Lilo Dec 09 '15 at 13:07
  • Dont confuse things : `std::exception`requires that `what` returns a `char const *`, but that does not mean you cant use `std::string` as storage underneath (ever heard of `std::string::c_str()` ?). Beside, I missed the fact that `KinectInitFailedException ` inherits from `ShoulderROMException`, I'll update my answer accordingly. – Jean-Bernard Jansen Dec 09 '15 at 13:43
  • And about virtual functions : a call to a virtual function implies a lookup into the virtual table, this is runtime polymorphism. An inlined function is a function which disappear since the code is directly "pasted" where you call it. This is a compile time choice. Therefore, a virtual function cannot be inlined. Your compiler ignores it in your case. – Jean-Bernard Jansen Dec 09 '15 at 13:50
1

Thanks for all your help. It got me inspired. With some additional ideas of a fellow student I came up with this solution which works great. :)

#include <exception>

class Exception :
    public std::exception {
private:
    static const std::string MESSAGE = "Exception";

protected:
    std::string composedMessage;

public:
    Exception() :
    composedMessage(this->MESSAGE) {
    }

    virtual const char* what() const throw() {
        return this->composedMessage.c_str();
    }
};

class ShoulderROMException :
    public Exception {
private:
    static const std::string MESSAGE = "ShoulderROM exception";

public:
    ShoulderROMException() {
        this->appendMessage(this->MESSAGE);
    }

    virtual void appendMessage(std::string message) {
        this->composedMessage += " -> ";
        this->composedMessage += message;
    }
};

class KinectInitFailedException :
    public ShoulderROMException {
private:
    static const std::string MESSAGE = "Kinect initialization failed.";

public:
    KinectInitFailedException() {
        this->appendMessage(this->MESSAGE);
    }
};

I looked at the problem from the wrong side: top-down instead of bottom-up. ^^

Thanks for your help anyway and best regards, Lilo

Lilo
  • 341
  • 2
  • 14
  • Why not pass in the constructor? Add a `std::string` parameter to the constructor of all three types, in each constructor append the message of the current type and pass the result to the base class constructor. – dyp Dec 09 '15 at 16:00
  • That would unneccessarily complicate throwing an exception, wouldn't it? – Lilo Dec 09 '15 at 16:33