成员初始化查询
Query about member initialization
当我在做 hackerrank c++ 练习时,我在讨论部分偶然发现了这段代码:
class BadLengthException : public std::runtime_error
{
public:
BadLengthException(int length) : std::runtime_error{std::to_string(length)}
{ }
};
我不太明白成员初始化部分之后发生了什么,确切地说是这部分:
std::runtime_error{std::to_string(length)}
谁能解释一下这行代码对我的作用?我从未见过这样使用成员初始化。我看惯了:
Foo(int num) : bar(num) {};
所以请尽可能解释清楚。感谢您的宝贵时间!
您正在继承标准异常 class std::runtime_error
。
在此代码中:
class BadLengthException : public std::runtime_error
{
public:
BadLengthException(int length) std::runtime_error{std::to_string(length)}
{ }
};
您正在根据 std::runtime_error
.
定义一个新的异常 class
std::runtime_error
将字符串消息作为输入,您可以在 catch
块中使用 runtime_error_object.what()
打印它。所以,这就是 length
变量被转换为 std::string
的原因。您可以阅读更多相关信息 here。
最后:
Foo(int num) : bar(num) {};
这是构造函数列表初始化语法。即用于初始化class的成员变量。您可以阅读更多相关信息 here。
首先,请注意基 class 与初始化列表中的任何其他成员具有相同的成员语法。说,你有一个基础 class:
class Base {
int m_val;
public:
explicit Base(int val) : m_val(val) {};
int val() const { return m_val; }
};
现在,您想要在派生的 class 中初始化 m_val
- 您不能,因为它对 Base
是私有的。但是您可以通过显式初始化派生 class“环绕”的基础 class 实例来初始化它:
class Derived {
int m_myVal;
public:
Derived() : Base(42), m_myVal(12) {
assert(val() == 42 && m_myVal == 12);
}
};
在 C++11 中,您可以使用新语法进行初始化。它被称为统一初始化语法。上面可以重写如下:
class Base {
int m_val;
public:
explicit Base(int val) : m_val{val} {};
int val() const { return m_val; }
};
// Approach 1
class Derived {
int m_dval;
public:
Derived() : Base{42}, m_myVal{12} {
assert(val() == 42 && m_myVal == 12);
}
};
// Approach 2
class Derived {
int m_dval = 12;
public:
Derived() : Base{42} {
assert(val() == 42 && m_myVal == 12);
}
};
因此,您的代码在上下文中:
namespace my {
// We make our own classes, equivalent to those in std::, for purpose of exposition:
class exception {
public:
exception() noexcept = default;
virtual ~exception() = default;
virtual const char* what() const noexcept { return ""; }
};
class runtime_error {
std::string m_what;
public:
explicit runtime_error(const std::string &what) : m_what(what) {}
const char* what() const noexcept override { return m_what.c_str(); }
};
}
class BadLengthException : public my::runtime_error {
public:
// pre-C++11 syntax
BadLengthException(int length) : my::runtime_error(std::to_string(length)) {
assert(what() == std::to_string(length));
}
// or, with C++11 syntax
BadLengthException(int length) : my::runtime_error{std::to_string(length)} {
assert(what() == std::to_string(length));
}
};
那里,my::runtime_error
是参考基础 class 编写的,以便将参数传递给它的构造函数。
在上面的代码中,assert
s 不仅仅是调试构建的运行时检查,它们还记录了关于代码的真实陈述。有一种用英语阅读它们的明确方法 - 一项很好的技能。
自然而然地倾向于写 评论 关于程序的预期状态:
// Don't do this
Derived::Derived() : Base{42} {
// Here val() is 42 and m_myVal is 12
}
这不是惯用的 C++:关于状态的注释会有所帮助,但永远不会使用代码不仅 正式 提出真实的陈述(断言),而且在运行时验证它。此外,代码优化器和静态分析工具可以利用断言。开悟后,经常会看到:
// Don't do this: don't repeat yourself (DRY)
Derived::Derived() : Base{42} {
assert(val() == 42 && m_myVal == 12);
// Here val() is 42 and m_myVal is 12
}
惯用的方法是仅使用断言 - 无需注释,按原样就很容易理解。
Derived::Derived() : Base{42} {
assert(val() == 42 && m_myVal == 12);
}
当我在做 hackerrank c++ 练习时,我在讨论部分偶然发现了这段代码:
class BadLengthException : public std::runtime_error
{
public:
BadLengthException(int length) : std::runtime_error{std::to_string(length)}
{ }
};
我不太明白成员初始化部分之后发生了什么,确切地说是这部分:
std::runtime_error{std::to_string(length)}
谁能解释一下这行代码对我的作用?我从未见过这样使用成员初始化。我看惯了:
Foo(int num) : bar(num) {};
所以请尽可能解释清楚。感谢您的宝贵时间!
您正在继承标准异常 class std::runtime_error
。
在此代码中:
class BadLengthException : public std::runtime_error
{
public:
BadLengthException(int length) std::runtime_error{std::to_string(length)}
{ }
};
您正在根据 std::runtime_error
.
std::runtime_error
将字符串消息作为输入,您可以在 catch
块中使用 runtime_error_object.what()
打印它。所以,这就是 length
变量被转换为 std::string
的原因。您可以阅读更多相关信息 here。
最后:
Foo(int num) : bar(num) {};
这是构造函数列表初始化语法。即用于初始化class的成员变量。您可以阅读更多相关信息 here。
首先,请注意基 class 与初始化列表中的任何其他成员具有相同的成员语法。说,你有一个基础 class:
class Base {
int m_val;
public:
explicit Base(int val) : m_val(val) {};
int val() const { return m_val; }
};
现在,您想要在派生的 class 中初始化 m_val
- 您不能,因为它对 Base
是私有的。但是您可以通过显式初始化派生 class“环绕”的基础 class 实例来初始化它:
class Derived {
int m_myVal;
public:
Derived() : Base(42), m_myVal(12) {
assert(val() == 42 && m_myVal == 12);
}
};
在 C++11 中,您可以使用新语法进行初始化。它被称为统一初始化语法。上面可以重写如下:
class Base {
int m_val;
public:
explicit Base(int val) : m_val{val} {};
int val() const { return m_val; }
};
// Approach 1
class Derived {
int m_dval;
public:
Derived() : Base{42}, m_myVal{12} {
assert(val() == 42 && m_myVal == 12);
}
};
// Approach 2
class Derived {
int m_dval = 12;
public:
Derived() : Base{42} {
assert(val() == 42 && m_myVal == 12);
}
};
因此,您的代码在上下文中:
namespace my {
// We make our own classes, equivalent to those in std::, for purpose of exposition:
class exception {
public:
exception() noexcept = default;
virtual ~exception() = default;
virtual const char* what() const noexcept { return ""; }
};
class runtime_error {
std::string m_what;
public:
explicit runtime_error(const std::string &what) : m_what(what) {}
const char* what() const noexcept override { return m_what.c_str(); }
};
}
class BadLengthException : public my::runtime_error {
public:
// pre-C++11 syntax
BadLengthException(int length) : my::runtime_error(std::to_string(length)) {
assert(what() == std::to_string(length));
}
// or, with C++11 syntax
BadLengthException(int length) : my::runtime_error{std::to_string(length)} {
assert(what() == std::to_string(length));
}
};
那里,my::runtime_error
是参考基础 class 编写的,以便将参数传递给它的构造函数。
在上面的代码中,assert
s 不仅仅是调试构建的运行时检查,它们还记录了关于代码的真实陈述。有一种用英语阅读它们的明确方法 - 一项很好的技能。
自然而然地倾向于写 评论 关于程序的预期状态:
// Don't do this
Derived::Derived() : Base{42} {
// Here val() is 42 and m_myVal is 12
}
这不是惯用的 C++:关于状态的注释会有所帮助,但永远不会使用代码不仅 正式 提出真实的陈述(断言),而且在运行时验证它。此外,代码优化器和静态分析工具可以利用断言。开悟后,经常会看到:
// Don't do this: don't repeat yourself (DRY)
Derived::Derived() : Base{42} {
assert(val() == 42 && m_myVal == 12);
// Here val() is 42 and m_myVal is 12
}
惯用的方法是仅使用断言 - 无需注释,按原样就很容易理解。
Derived::Derived() : Base{42} {
assert(val() == 42 && m_myVal == 12);
}