MAChitgarha
MAChitgarha

Reputation: 4298

Using constructor of one of the base classes without other base class having default constructor in multiple inheritance

I'm trying to design a custom exception hierarchy. What I want is, to inherit from standard exceptions and errors as much as possible, to allow catching custom exceptions in the case of catching STL ones.

For instance, in the following hierachy, if you catch an instance of std::logic_error, then an instance of LogicException will also be caught:

                -> Exception --> LogicException
               /                      ^
std::exception --> std::logic_error --^

So, this is the code to achieve this (excluding header guard, includes and namespace scopes, and definitions):

class Exception: public std::exception
{
    public:
        Exception() = delete;
        Exception(const char *) noexcept(true);
        Exception(const std::string &) noexcept(true);

        virtual Message what() const noexcept(true);

    private:
        std::string message;
};

class LogicException: public Exception, public std::logic_error
{
    public:
        LogicException() = delete;
        using Exception::Exception;

        using Exception::what;
};

However, considering the following basic main function (again, excluding non-sense parts):

int main()
{
    throw LogicException("Oops!");
}

I'll get the following error (compiling with GCC 10.0.1):

test.cpp: In function ‘int main()’:
test.cpp:5:29: error: use of deleted function ‘LogicException::LogicException(const char*) [inherited from Exception]’
    5 |     throw LogicException("e");
      |                             ^
In file included from test.cpp:1:
./include/exception.hpp:27:34: note: ‘LogicException::LogicException(const char*) [inherited from Exception]’ is implicitly deleted because the default definition would be ill-formed:
   27 |                 using Exception::Exception;
      |                                  ^~~~~~~~~
./include/exception.hpp:27:34: error: no matching function for call to ‘std::logic_error::logic_error()’
In file included from ./include/exception.hpp:4,
                 from test.cpp:1:
/usr/include/c++/10/stdexcept:131:5: note: candidate: ‘std::logic_error::logic_error(const std::logic_error&)’
  131 |     logic_error(const logic_error&) _GLIBCXX_NOTHROW;
      |     ^~~~~~~~~~~
/usr/include/c++/10/stdexcept:131:5: note:   candidate expects 1 argument, 0 provided
/usr/include/c++/10/stdexcept:126:5: note: candidate: ‘std::logic_error::logic_error(std::logic_error&&)’
  126 |     logic_error(logic_error&&) noexcept;
      |     ^~~~~~~~~~~
/usr/include/c++/10/stdexcept:126:5: note:   candidate expects 1 argument, 0 provided
/usr/include/c++/10/stdexcept:124:5: note: candidate: ‘std::logic_error::logic_error(const char*)’
  124 |     logic_error(const char*) _GLIBCXX_TXN_SAFE;
      |     ^~~~~~~~~~~
/usr/include/c++/10/stdexcept:124:5: note:   candidate expects 1 argument, 0 provided
/usr/include/c++/10/stdexcept:120:5: note: candidate: ‘std::logic_error::logic_error(const string&)’
  120 |     logic_error(const string& __arg) _GLIBCXX_TXN_SAFE;
      |     ^~~~~~~~~~~
/usr/include/c++/10/stdexcept:120:5: note:   candidate expects 1 argument, 0 provided

So, the questions are:

Thanks.

Upvotes: 0

Views: 51

Answers (1)

Wolf
Wolf

Reputation: 10238

I'm not sure if you really want to build another exception hierarchy along with that of std::exception (maybe I just don't get your point). As to build an exception hierarchy onto std::exception (and its children), you don't need another base.

What to throw

Since you should anyway never throw unspecific exceptions, because you will not be able to handle it in a specific way at the caller side, only add specific leaves to the existing exception hierarchy your platform supports. If you are programming standard C++, this is the std::exception hierarchy.

What to catch

You should be very careful with catching std::exception. I'd suggest to do this only in main (or an equivalent top-level function) as to log an error before exiting. Exceptions that you are allowed to catch are those whose conditions you understand and which you have complete control over; for instance that a file doesn't exist that the program has alternatives for or doesn't need it at all (because ist's just optional).

what to message

As I understand it, the what() property is an original message from the place where the "accident" happened, it gives additional information that your program shouldn't bind to.[1] It's for "forensics" mostly just for generating output (for displaying on user interface or adding to log file). See the following small demo of my understanding:

#include <iostream>
#include <stdexcept>

class my_ex: public std::logic_error {
public:
    my_ex(const char* const what): std::logic_error(what) {}
};

void just_throw_the_message(const char* const msg) {
    throw my_ex(msg);
}

int main() {
    try {
        just_throw_the_message("I feel somewhat exceptional.");
    } catch (const std::exception& e) {
        std::cout << "exception caught: " << e.what() << std::endl;
    }
    return 0;
}

(see above code running at ideone.com)

Conclusion

Your initial statement was (emphasis mine):

What I want is, to inherit from standard exceptions and errors as much as possible, to allow catching custom exceptions in the case of catching STL ones.

The only reasonable answer I see to this requirement is to derive your class directly from std::exception or one of its descendants! Don't use multiple inheritance for exceptions! Especially, as much as possible, is not much more than the error classification already defined by the hierarchy you build onto. So when in standard C++, I highly recommend inheriting (ultimately) from std::exception.

If you already have an application-specific exception hierarchy that fits you needs, just make its base class a descendant of std::exception.


[1] As to distinguish exceptional events programmatically, use the exception type. It also makes sense to add properties to your own program-specific exception class(es).

Upvotes: 1

Related Questions