在不显式传递实例的情况下从内部 class 访问外部 class
Accessing outer class from inner class without explicitly passing an instance
以下代码产生输出
outer::inner::inner, o=00000000
outer
outer::inner::val, o=00000000
outer::print
任何人都可以解释我如何通过 o
访问外部 class 方法 print
而无需在构造时显式分配 o
的值吗?
这里o
为空,但我仍然可以调用它的方法。
我已经用 MSVC 2017 和 g++ 7.4.0 测试过,输出是一样的。
#include <iostream>
class outer {
public:
outer() {
std::cout << __func__ << std::endl;
}
class inner {
outer *o = nullptr;
public:
inner() {
std::cout << __FUNCTION__ << ", o=" << o << std::endl;
}
void val() {
std::cout << __FUNCTION__ << ", o=" << o << std::endl;
o->print(); // **call outer class method**
}
};
inner i;
void print() {
std::cout << __FUNCTION__ << std::endl;
}
};
int main()
{
outer o;
o.i.val();
return 0;
}
您可以将示例简化为
struct S
{
void f() { std::cout << "hello world\n"; }
};
int main()
{
S* s = nullptr;
s->f();
}
并且取消引用nullptr
是UB。所以任何事情都有可能发生。
为什么它看起来有效?
因为在实践中,方法函数通常被实现为好像有带有额外参数的常规函数:
void S::f()
-> void f(S*)
(或void f(S&)
)
等等,代码变成:
void f(S* /*unused*/) { std::cout << "hello world\n"; }
int main()
{
S* unused = nullptr;
f(unused);
}
在这种情况下,编译器将 UB 转换为有效代码,因为 unused
未被使用,它不会崩溃并执行您期望的操作。
以下代码产生输出
outer::inner::inner, o=00000000
outer
outer::inner::val, o=00000000
outer::print
任何人都可以解释我如何通过 o
访问外部 class 方法 print
而无需在构造时显式分配 o
的值吗?
这里o
为空,但我仍然可以调用它的方法。
我已经用 MSVC 2017 和 g++ 7.4.0 测试过,输出是一样的。
#include <iostream>
class outer {
public:
outer() {
std::cout << __func__ << std::endl;
}
class inner {
outer *o = nullptr;
public:
inner() {
std::cout << __FUNCTION__ << ", o=" << o << std::endl;
}
void val() {
std::cout << __FUNCTION__ << ", o=" << o << std::endl;
o->print(); // **call outer class method**
}
};
inner i;
void print() {
std::cout << __FUNCTION__ << std::endl;
}
};
int main()
{
outer o;
o.i.val();
return 0;
}
您可以将示例简化为
struct S
{
void f() { std::cout << "hello world\n"; }
};
int main()
{
S* s = nullptr;
s->f();
}
并且取消引用nullptr
是UB。所以任何事情都有可能发生。
为什么它看起来有效?
因为在实践中,方法函数通常被实现为好像有带有额外参数的常规函数:
void S::f()
-> void f(S*)
(或void f(S&)
)
等等,代码变成:
void f(S* /*unused*/) { std::cout << "hello world\n"; }
int main()
{
S* unused = nullptr;
f(unused);
}
在这种情况下,编译器将 UB 转换为有效代码,因为 unused
未被使用,它不会崩溃并执行您期望的操作。