这是使用继承的好方法吗?

Is this a good way of using inheritance?

本文关键字:方法 继承      更新时间:2023-10-16

这是使用继承的好方法吗?

#include <iostream>
namespace Test::A {
class A {
char const * const this_message;
public:
constexpr A(char const * const message) noexcept
: this_message(message) {
}
constexpr char const * message() const noexcept {
return this_message;
}
};
struct B : public A {
constexpr B(char const * const message) noexcept
: A(message) {
}
};
}
int main() {
std::cout << sizeof(Test::A::A) << 'n';
std::cout << sizeof(Test::A::B) << 'n';
std::cout << Test::A::B("Test 1").message() << 'n';
try {
char const * const Test4 = "Test 4";
// Uncomment / comment to toggle between
//throw Test::A::B("Test 1");
throw Test::A::B(Test4);
} catch (Test::A::A const a) {
// I'm passing 'a' by copy because the size of 'a'
// will always be either 4 or 8 bytes / it's faster this way.
constexpr auto message = Test::A::B("Test 3").message();
std::cout << a.message() << " " << message << 'n';
}
return 0;
}

我有两个问题:

A) 这是使用继承和...

B) 这个程序是否正确,格式良好,没有未定义的行为?

我想创建我自己的简单两级异常层次结构(只有一个基类和一些派生类),我正在尝试找到一种没有任何虚拟方法的方法。

下面的代码确实有效,它似乎以正确的顺序调用析构函数,即使派生类上没有任何要破坏的内容。然而,我对这个内部是如何工作的有点困惑。

我知道如果我希望通过其基指针删除派生类,我需要一个虚拟析构函数,但我没有考虑支持这种多态性。

我知道通过从B调用message方法,我只是从A调用该方法,而该方法又只返回成员变量this_message,可以在AB中初始化。

将对象传递给 catch 调用时,B对象是否通过切片过程变成了A?但是因为 B 只是初始化了A/的成员,与A具有相同的状态,所以最终一切都解决了。

这个想法是通过传递包含行号、文件位置等的静态 char 数组,在宏中初始化A类及其派生类。

我知道如果

我希望通过其基指针删除派生类,我需要一个虚拟析构函数,但我没有考虑支持这种多态性。

如果你是唯一一个从事项目的程序员,那么这种妥协可能是实用的,但你需要与加入项目的每个人沟通和执行,所以你很难扩展或重用你编写的代码。

将对象传递给 catch 调用时,B 对象是否通过切片过程变成了 A?但是因为 B 只是初始化了 A 的成员/与 A 具有相同的状态,所以最终一切都解决了。

是的,通过切片。 是的,它挂在一起。

这个想法是通过传递包含行号、文件位置等的静态 char 数组,在宏中初始化 A 类及其派生类。

这是另一个问题/陷阱:人们习惯于std::exception在内部std::string中捕获文本,因此必须警告其他程序员不要做Test::A::B(my_message_in_a_string.c_str());Test::A::B(my_ostringstream.str())之类的事情,这使得将有用的消息放入异常类变得更加困难。

A) 这是使用继承和...

它授予了按基类型(无论是通过引用还是切片)或派生类型捕获的选项,因此继承增加了有用的功能。

B) 这个程序是否正确,格式良好,没有未定义的行为?

它是,但面对维护,它很脆弱,并且由于缺乏虚拟功能和切片的使用,很难扩展。

您使用的是标准库 std::cout,因此您绝对应该从 std::exception 中派生您的异常。

类的名称应该正确命名,例如 SomethingException。

使用指针初始化类似乎错误,即使它是指向 .const 部分中的内容。您已经初始化了堆栈中要展开的指针。该指针将在类实例中的复制之前死亡,因为它被抛出。它将起作用,因为地址是 .const 但它闻起来,会导致未来的维护者挠头。

所以: A - 不是一种好的继承形式。 B - 行为被定义,尽管很臭;-)