简体   繁体   English

C ++ Exception在虚函数上抛出注释

[英]C++ Exception throw annotations on virtual functions

I saw the following snippet code: 我看到了以下代码段:

class Foo
{
public:
        void virtual func() throw (int, float) = 0;
};

class Bar : public Foo
{
public:
        void virtual func() throw(short);      // line 1: compile error "
                                                                      // looser throw specifier"
        void virtual func() throw();                // line 2: can compile
        void virtual func() throw(float, int); // line 3: can compile
        void virtual func() throw(float);        // line 4: can compile
        void virtual func() throw(int);           // line 5: can compile

};

int main(void)
{
        return 1;
}

Q1> What is meaning of Q1>是什么意思

void virtual func() throw (int, float) = 0;

Q2> why line1 cannot pass the compiler? Q2>为什么line1无法通过编译器?

Thank you 谢谢

Let's break this down. 让我们打破这个。 The declaration: 声明:

void virtual func() throw (int, float) = 0;

has 2 constructs that you're asking about. 有两个你要问的结构。 the =0 construct tells the compiler that the declared function is 'abstract', which tells the compiler that the function need not be defined in the class Foo (though it can be - but it usually isn't) and that an object of class Foo cannot be directly created - either as a local, global or via new . =0结构告诉编译器声明的函数是'abstract',它告诉编译器函数不需要在class Foo定义(尽管它可以是 - 但通常不是)并且是class Foo的对象class Foo不能直接创建 - 无论是本地,全局还是new However, you can have pointers or references to objects of class Foo . 但是,您可以拥有指向class Foo对象的指针或引用。 Some derived class needs to override the function as a non-abstract function - objects of that class can be directly created (as long as there are no other abstract functions that haven't been made 'concrete'). 某些派生类需要将该函数覆盖为非抽象函数 - 可以直接创建该类的对象(只要没有其他抽象函数没有“具体”)。

The throw (int, float) construct is an exception specifification. throw (int, float)构造是一个异常规范。 This tells the compiler that the function's contract is that it will only throw exceptions of type int or float if it throws an exception. 这告诉编译器函数的契约是它只会抛出intfloat类型的异常,如果它抛出异常。 If the function throws some other kind of exception, the compiler is obligated to handle that specially (by calling std::unexpected() ). 如果函数抛出其他类型的异常,编译器有义务专门处理(通过调用std::unexpected() )。

Now, if you try to override that function in a derived class with the following declaration: 现在,如果您尝试使用以下声明覆盖派生类中的该函数:

void virtual func() throw(short);

You're saying that the function's contract is that it will throw exceptions of type short if an exception is thrown. 你说的是函数的契约是如果抛出异常它会抛出short类型的异常。 However, throwing short is not part of the contract of the function being overridden, so the compiler doesn't permit it. 但是,抛出short并不是被覆盖函数的契约的一部分,因此编译器不允许它。

If you declare the override like so: 如果你像这样声明覆盖:

void virtual func() throw(float);

You're saying that the override can throw a float , which is part of the contract of the original declaration (if it never throws an int that doesn't break the contract - the original contract only says that the function is allowed to throw an int , not that it has to). 你说覆盖可以抛出一个float ,这是原始声明的合同的一部分(如果它从不抛出一个不破坏合同的int - 原始合同只说该函数允许抛出一个int ,而不是它必须)。

The relevant part of the standard is 15.4/3 Exception specifications: 标准的相关部分是15.4 / 3异常规范:

If a virtual function has an exception-specification, all declarations, including the definition, of any function that overrides that virtual function in any derived class shall only allow exceptions that are allowed by the exception-specification of the base class virtual function. 如果虚函数具有异常规范,则在任何派生类中覆盖该虚函数的任何函数的所有声明(包括定义)都应仅允许基类虚函数的异常规范所允许的异常。

Note that the standard explicitly states that an exception specification is not part of the function's type (15.4/12), so a function pointer can, for example, point to functions that have different exception specifications. 请注意,标准明确声明异常规范不是函数类型的一部分(15.4 / 12),因此函数指针可以指向具有不同异常规范的函数。

You're defining the same function signature many times. 您多次定义相同的函数签名。 The different throw() qualifiers are not enough to disambiguate the functions. 不同的throw()限定符不足以消除函数的歧义。

The throw() qualifier simply means that the specified function is only expected to throw the types listed in the parenthesis following the qualifier. throw()限定符只是意味着指定的函数只能抛出限定符后括号中列出的类型。 However, this does not actually prevent the function from throwing. 但是,这实际上并不会阻止函数抛出。 Rather, if the function actually does throw any unlisted types, your program will terminate. 相反,如果该功能实际上抛出任何未上市的类型,你的程序将终止。

The function you're defining in the base class is making a guarantee - it can only throw an int or a float . 您在基类中定义的函数正在保证 - 它只能抛出一个intfloat Your line 1 is failing because it's breaking the guarantee by saying it will throw a short , which isn't either of the above. 你的第1行是失败的,因为它会破坏保证,说它会抛出一个short ,这不是上述任何一种。

The = 0 in Q1 declares that each derived class that you try to create an instance of will need to provide its own declaration and implementation of this function. Q1中的= 0声明您尝试创建实例的每个派生类都需要提供自己的声明和此函数的实现。 The base class may also provide an implementation, but typically it doesn't. 基类也可以提供实现,但通常不提供。

The meaning of named throw statements is to declare that a function can only throw those named exceptions either directly or indirectly. named throw语句的含义是声明一个函数只能直接或间接地抛出那些命名的异常。

So the line: 所以行:

void virtual func() throw(int, float) =0;

means that whatever class inherits this base type it is only allowed to throw either an int or a float. 表示无论哪个类继承此基类型,都只允许抛出int或float。 It can not either directly or indirectly throw any other type of exception or object. 它不能直接或间接抛出任何其他类型的异常或对象。 If it does, it will call the unexcepted() function. 如果是,它将调用unexcepted()函数。 By default this calls the terminate() function. 默认情况下,它调用terminate()函数。 You're allowed to reset that using the set_unexpected function but still. 您可以使用set_unexpected函数重置它,但仍然可以。

By choosing to add those throw statements to your interface you're really limiting yourself. 通过选择将这些throw语句添加到您的界面,您实际上是在限制自己。

When you override a virtual function any exception specifier that you provide must be at least as restrictive as that specified on the function that you are overriding. 覆盖virtual函数时,您提供的任何异常说明符必须至少与您要覆盖的函数上指定的限制符一样严格。 This prevents the base class' exception specification from being violated. 这可以防止违反基类的异常规范。

As the base class' exception specifier [ throw (int, float) ] does not allow a short to be thrown, the derived class cannot allow a short to be thrown. 由于基类的异常说明符[ throw (int, float) ]不允许抛出short ,派生类不允许抛出short At most it may allow an int and/or a float ; 最多可以允许int和/或float ; it may allow only either one or neither to be thrown as any of these possibilities would be more restrictive than the exception specification of the base class function. 它可能只允许抛出一个或两个抛出,因为这些可能性中的任何一个都比基类函数的异常规范更具限制性。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM