C++ C++;抛出取消引用的指针
下面抛出的异常对象的类型是什么: 问题1>范围错误(“错误”);投掷r代码> 回答1>范围错误的对象 问题2>异常*p=&r;投掷*p代码> 回答2>异常的切片对象 问题3>异常*p=&r;投掷p代码> Answer3>抛出指向范围_错误的指针。捕获处理可以通过动态绑定访问range_error成员函数 我对这些问题理解正确吗 //更新、编译并在VS2010上运行C++ C++;抛出取消引用的指针,c++,C++,下面抛出的异常对象的类型是什么: 问题1>范围错误(“错误”);投掷r 回答1>范围错误的对象 问题2>异常*p=&r;投掷*p 回答2>异常的切片对象 问题3>异常*p=&r;投掷p Answer3>抛出指向范围_错误的指针。捕获处理可以通过动态绑定访问range_error成员函数 我对这些问题理解正确吗 //更新、编译并在VS2010上运行 #include <iostream> using namespace std; class ExClassA { public:
#include <iostream>
using namespace std;
class ExClassA
{
public:
virtual void PrintMe() const
{
cout << "ExClassA" << endl;
}
};
class ExClassB : public ExClassA
{
public:
virtual void PrintMe() const
{
cout << "ExClassB" << endl;
}
};
int main(int argc, char* argv[])
{
ExClassB exClassB;
ExClassA *p = &exClassB;
try
{
throw *p;
}
catch (const ExClassA& e)
{
e.PrintMe();
}
try
{
throw p;
}
catch (const ExClassA* e)
{
e->PrintMe();
}
}
#包括
使用名称空间std;
类感叹号
{
公众:
虚空PrintMe()常量
{
cout我认为你在这三个方面都是对的。抛出对象的类型(IIRC)是被抛出对象的静态类型。我必须深入标准一段时间才能找到确切的引号,但一个简单的例子似乎证实了这一点:
struct base {};
struct derived : base {};
void t() {
derived d;
base * b = &d;
throw *b;
}
int main() {
try {
t();
} catch ( derived const & ) {
std::cout << "derived" << std::endl;
} catch ( base const & ) {
std::cout << "base" << std::endl;
}
}
struct base{};
派生结构:基{};
void t(){
导出d;
基数*b=&d;
投掷*b;
}
int main(){
试一试{
t();
}捕获(派生常量&){
std::cout根据对象的静态类型,抛出对象总是导致抛出对象是您抛出对象的副本。因此,您的前两个答案是正确的
第三个比较复杂。如果catch(range\u error*)
则不会捕获异常,因为类型不匹配。如果catch(exception*)
您将无法在捕获的指针中访问范围\u错误的成员;您可以动态\u将该指针转换回范围\u错误指针。所有三个答案都是正确的。请注意,您必须捕获一个
第三种情况下的指针类型
引发异常的常用方法是:
throw range_error("error");
在抛出站点上,您通常知道您所遇到的异常的确切类型
我想扔。我能想到的唯一例外是
异常作为参数传入,例如:
void f( std::exception const& whatToDoInCaseOfError )
{
// ...
throw whatToDoInCaseOfError; // slices
}
这不是一个频繁的案例,但如果你想支持它,你需要一个
使用虚拟的raise
功能:
class MyExceptions
{
public:
virtual ~MyExceptions() {}
virtual void raise() const = 0;
};
template<typename ExceptionType>
class ConcreteException : public ExceptionType, public MyExceptions
{
public:
virtual void raise() const
{
throw *this;
}
};
类MyExceptions
{
公众:
虚拟~MyExceptions(){}
虚空raise()常量=0;
};
模板
类ConcreteException:PublicExceptionType,PublicMyExceptions
{
公众:
虚空raise()常量
{
扔掉这个;
}
};
然后,客户机代码封装了他希望抛出的异常
ConcreteException
,您在其上调用raise
函数,而不是
而不是直接调用throw
。参考:Lippman 17.1。这取决于你说“新”时的想法@Kerrek,我曾想过“新”可能会引起混淆,我已将其从OP中删除。相关标准见§15.1/3。@David,结构继承的默认修饰符是公共的吗?@q0987:类
和结构
之间的唯一区别是类的默认访问说明符
是私有的
,而for结构的
是公共的。这既适用于继承,也适用于成员访问。此外,向局部变量抛出指针是错误的。RAII将清除该变量,指针将被删除DEAD@Bob好的一点是,我没有想到。捕获的异常是通常意义上的局部变量,还是很特殊mehow?这只会在抛出指针时出现,您只需确保指针指向有效的对象。当您按值(不是指针)抛出某个对象时所以捕获的异常是一个局部变量,它是抛出的异常的副本。@马克,你能检查我的更新吗?第二个try-catch打印的是我期望的内容,而不是你说的内容。@q0987,你在ClassA
指针上调用一个虚拟函数,所以它的工作原理与任何其他变形相同ic指针。我在回答中的意思是,您无法访问对象中ClassB
的任何非虚拟函数或数据成员。我们只需将代码从“throw whattodoincaseofer;”替换为“throw”为了避免切片问题。如果我没记错的话,以这种方式重试不会导致切片问题。@q0987但我们不能重试,除非我们在某个catch块中,在这种情况下,客户端不必传入异常。