Inheritance of constructors and virtual base classes

I am going to create a hierarchy of exception classes that conceptually looks something like this:

#include <iostream> #include <stdexcept> class ExceptionBase : public std::runtime_error { public: ExceptionBase( const char * msg ) : std::runtime_error(msg) {} }; class OperationFailure : virtual public ExceptionBase { public: using ExceptionBase::ExceptionBase; }; class FileDoesNotExistError : virtual public ExceptionBase { public: using ExceptionBase::ExceptionBase; }; class OperationFailedBecauseFileDoesNotExistError : public OperationFailure, FileDoesNotExistError { public: using ExceptionBase::ExceptionBase; // does not compile }; int main() { OperationFailedBecauseFileDoesNotExistError e("Hello world!\n"); std::cout << e.what(); } 

All constructors should look the same as the constructor of the ExceptionBase class. Exceptions received differ only in type, otherwise there is no added functionality. The last type of exception mentioned in the code above should also have these constructors. Is it possible to use the function of the inheriting constructors of the C ++ 11 standard? If this is not possible: what are the alternatives?

(By the way: in the above code, the classes OperationFailure and FileDoesNotExistError did not compile with gcc 4.8, but with clang 3.4. Obviously, gcc rejects the inheritance of constructors for virtual databases. It would be interesting to know who Both compilers rejected the class OperationFailedBecauseFileDoesNotExistError , because the inheriting constructor does not inherit from the direct base.)

+6
source share
2 answers

When the use declaration is used to inherit constructors, this requires a direct base class [namespace.udecl] / 3

If such a utility declaration is called by the constructor, the sub-name specifier must indicate the direct base class of the class being defined; otherwise, it enters the set of ads found when searching for the member name.

those. in your case, the use-declaration in OperationFailedBecauseFileDoesNotExistError does not inherit, but re-declares (as an alias) or displays the name ctor ExceptionBase .

You need to write a non-inheriting ctor for OperationFailedBecauseFileDoesNotExistError .


By the way, this is normal for non-virtual base classes: the declaration of use for ctors inheritance is rewritten as:

 //using ExceptionBase::ExceptionBase; OperationFailure(char const * msg) : ExceptionBase( static_cast<const char*&&>(msg) ) {} 

Since you can only initialize a direct base class (or virtual base class) in the mem-initializer list, it makes sense for non-virtual base classes to restrict the use of declarations to inheriting ctors only from direct base classes.

The authors of the ctors inheritance proposal knew that this violated the support for the ctors virtual base classes, see N2540 :

As a rule, inheritance of design definitions for classes with virtual databases will be poorly formed, unless the virtual database supports initialization by default, or the virtual database is a direct database and is called a redirected database. Similarly, all data members and other direct databases must support initialization by default, or any attempt to use the inheriting constructor will be poorly formed. Note: poorly formed when used, not announced.

+2
source

Inhering constructors are similar to entering shell functions for all the constructors you specify. In your case, you must call the specific constructors of both OperationFailure and FileDoesNotExistError , but the wrappers you enter will only call one of them.


I just checked out the latest C ++ 11 project (section 12.9), but actually it clearly does not cover your case.

+1
source

Source: https://habr.com/ru/post/956064/


All Articles