A. *_*ski 6 c++ using-declaration language-lawyer
考虑以下代码:
class user_error : public std::runtime_error
{
public:
using std::exception::what;
explicit user_error(const std::string& what_arg):std::runtime_error(what_arg){}
};
class with_overriden_what : public user_error {
public:
with_overriden_what(const std::string& val) : user_error("user_error"), message(val) { }
std::string message;
virtual const char* what() const noexcept {
return message.c_str();
}
};
Run Code Online (Sandbox Code Playgroud)
通过这个电话:
with_overriden_what ex("thrown");
std::cout << "1. direct result: " << ex.what() << "\n";
std::cout << "2. sliced result: " << static_cast<user_error>(ex).what() << "\n";
std::cout << "3. ranged result: " << ex.user_error::what() << "\n";
Run Code Online (Sandbox Code Playgroud)
令我惊讶的是,2和3的结果是不同的:
1. direct result: thrown
2. sliced result: user_error
3. ranged result: std::exception
Run Code Online (Sandbox Code Playgroud)
问:标准中是否有一个段落可以解决这种问题?
2.和3.的区别在于2.使用动态(==虚拟)调度(==调用)。当调用虚函数时,隐式使用动态调度(有关例外情况,请参阅后面的段落)。因此 2. 调用最派生的重写,它根据构造函数的后置条件的要求std::runtime_error::what打印提供给构造函数的消息:"user_error"
[运行时错误]
runtime_error(const char* what_arg);4 作用:构造一个runtime_error类的对象。
5 后置条件:
strcmp(what(), what_arg) == 0.
使用作用域解析运算符的函数调用会进行静态调度,即使该函数是虚拟的也是如此。
[类.虚拟]
15 作用域运算符 (5.1) 的显式限定会抑制虚拟调用机制。
因此,覆盖对于 3 来说并不重要。重要的是名称解析。using 声明与任何其他成员声明一样,它隐藏了本来可以从父级解析的相同名称。
所以,user_error::what隐藏std::runtime_error::what。并且,user_error::what由 定义std::exception::what。
std::exception::what现在,根据标准,这个非虚拟调用应该返回什么呢?(由我注释):
[例外]
7 返回:实现定义的 NTBS。(以空字符结尾的字符串)
显然,不需要打印任何特定内容,例如打印传递给包含 this 作为子对象的派生类的构造函数的字符串。任何字符串都符合标准。
该行为的最小示例,不涉及异常:
#include <iostream>
struct A {
virtual void x() {
std::cout << "A\n";
}
};
struct B : A {
void x() {
std::cout << "B\n";
}
};
struct C : B {
using A::x;
};
int main() {
C c;
c.x();
c.C::x();
return 0;
}
Run Code Online (Sandbox Code Playgroud)
两条线的输出必须不同。
| 归档时间: |
|
| 查看次数: |
139 次 |
| 最近记录: |