繁体   English   中英

异常对象的静态类型

[英]Static type of the exception object

我从C ++ Primer(第5版,第18.1.1节)中读到以下内容:“当我们抛出一个表达式时,该表达式的静态编译时类型决定了异常对象的类型。” 所以我尝试了以下代码:

#include <iostream>

class Base{
  public:
  virtual void print(std::ostream& os){os << "Base\n";}
};

class Derived: public Base{
  public:
  void print(std::ostream& os){os << "Derived\n";}
};

int main(){
  try{
    Derived d;
    Base &b = d;
    b.print(std::cout); //line 1
    throw b;
  }
  catch(Base& c){
    c.print(std::cout); //line 2
  }
return 0;
}

这给了我以下输出:

Derived
Base

我想我理解为什么这个输出是预期的:在第1行,我们有动态绑定。 现在当我们抛出b时,它基于b的静态类型,这意味着c的静态类型和动态类型都是Base&,因此我们在第2行看到结果。

但是,如果我使用指针而不是引用:

 int main(){
  try{
    Derived d;
    Base *b = &d;
    b->print(std::cout); //line 1
    throw b;
  }
  catch(Base* c){
    c->print(std::cout); //line 2
  }
return 0;
}

输出现在变为:

Derived
Derived

这似乎意味着c的静态类型是Base *,但c的动态类型是Derived *,为什么呢? 不应该是静态和动态类型的c都是Base *?

当我们抛出一个表达式时,该表达式的静态编译时类型决定了异常对象的类型

以上是完全正确的。 你忘了,指针也是对象。 当你抛出一个指针时, 那就是你的异常对象

对象应具有动态分配1通过仍指出, Base*指针。 并且没有切片发生,因为没有尝试复制它。 因此,动态分派via-pointer访问Derived对象,该对象将使用覆盖函数。

这种“差异”是为什么通常最好在throw表达式本身中构造异常对象。


1那个指针指向一个本地对象,你做了一个很大的不,没有那里,并给自己一个悬垂的指针。

在第一种情况下,您将抛出一个新的Base类实例来调用复制构造函数,因为您将对Base的引用传递给throw运算符。

在第二种情况下,您抛出指向类型为Derived的堆栈分配对象的指针,该对象在抛出异常时超出范围,因此您捕获然后取消引用导致未定义行为的悬空指针。

第一种情况

我认为如果你在课堂上添加一些印刷品,你会看到更清晰的画面:

struct Base {
    Base() { std::cout << "Base c'tor\n"; }
    Base(const Base &) { std::cout << "Base copy c'tor\n"; }

    virtual void print(std::ostream& os) { std::cout << "Base print\n"; }
};

struct Derived: public Base {
    Derived() { std::cout << "Derived c'tor\n"; }
    Derived(const Derived &) { std::cout << "Derived copy c'tor\n"; }

    virtual void print(std::ostream& os) { std::cout << "Derived print\n"; }
};

输出是:

Base c'tor
Derived c'tor
Derived print
throwing // Printed right before `throw b;` in main()
Base copy c'tor
Base print

如你所见,当调用throw b; 有一个异常的不同临时Base对象的副本构造。 来自cppreference.com

首先,从表达式复制初始化异常对象

此复制初始化会对对象进行切片 ,就像您指定了Base c = b

第二种情况

首先,您正在抛出一个指向本地对象的指针,导致未定义的行为 ,请务必避免这种情况!

假设您修复了这个问题,并且抛出一个动态分配的指针,它会起作用,因为您抛出的指针不会影响对象并保留动态类型信息。

暂无
暂无

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

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