在将其类型转换为 Derived class 指针后,从 Base class 指针调用 Derived class 函数
Calling Derived class function from a Base class pointer after typecasting it to Derived class pointer
我是 C++(和 OOP)的新手。我正在努力理解以下代码:
#include <iostream>
class Base {
public:
Base() {
std::cout << "In Base Constr: " << __FUNCSIG__ << std::endl;
}
virtual ~Base() {
std::cout << "In Base Destr: " << __FUNCSIG__ << std::endl;
}
void A() {
std::cout << "In Base func A " << __FUNCSIG__ << std::endl;
}
};
class Derived : public Base {
public:
Derived() {
std::cout << "In Derived Constr: " << __FUNCSIG__ << std::endl;
}
~Derived() {
std::cout << "In Derived Destr: " << __FUNCSIG__ << std::endl;
}
void B() {
std::cout << "In Derived func B " << __FUNCSIG__ << std::endl;
}
};
void test(Base* b) {
Derived* d = static_cast<Derived*>(b);
d->A();
d->B(); // How is this valid??
}
int main() {
Base *b = new Derived();
std::cout << "In main" << std::endl;
b->A();
std::cout << __LINE__ << std::endl;
Base *bb = new Base();
std::cout << __LINE__ << std::endl;
test(bb);
delete b;
delete bb;
}
我不确定,d->B()
行为何以及如何工作?即使指针被类型转换为 Derived class,但 Base class 对象本身不应在内存中具有该函数。
无效。这是未定义的行为。
问题是编译器允许您编写这样的代码。如果指向的对象实际上是 Derived
,则从 Base*
转换为 Derived*
将是有效的。由您作为程序员来确保它是有效的。
在C++中有很多情况你可以像这样搬起石头砸自己的脚。它是语言的一部分。
越界访问、取消引用悬挂 pointers/references 和无效强制转换,仅举几个最常见的例子。
当对象实际上不是该派生类型时,static_cast
到派生 class 是未定义的行为。但是未定义的行为意味着任何事情都可能发生,包括看似有效。 (或者今天似乎工作,然后在最糟糕的时间失败。)
官方从C++语言的角度解释到此为止。
但至于为什么这可能适用于典型的真实编译器和计算机:成员函数的代码实际上并未存储在对象内部,因为那会占用很多字节。对于非虚函数,对象内部甚至没有任何指向该函数的指针或类似的东西。相反,编译器将像非成员函数一样实现函数 Derived::B
:
void __mangled_Derived_B(Derived const* this) { /*...*/ }
然后每次调用B
函数时,它都会传递正确的指针成为“this
”参数。
在您的示例中,Derived::B
实际上根本没有使用 this
,甚至没有隐式使用,因此不太可能出现问题。但如果它试图使用 Derived
的数据成员,事情就会变得更加危险,可能会导致奇怪的结果、对其他对象的更改或崩溃。
I am not sure, why & how the line b->B() works? [..] the Base class object itself should not have that function in memory
你说得对!它没有 工作!
(嗯,函数没有存储 "in memory",但是…)
调用无效。 static_cast
表示 "I promise that this Base*
points to a Derived
"。这个承诺被打破了。
程序有未定义的行为。这在实践中可能意味着事情 "appear" 可以工作,特别是如果没有成员变量被不存在的函数触及...
我是 C++(和 OOP)的新手。我正在努力理解以下代码:
#include <iostream>
class Base {
public:
Base() {
std::cout << "In Base Constr: " << __FUNCSIG__ << std::endl;
}
virtual ~Base() {
std::cout << "In Base Destr: " << __FUNCSIG__ << std::endl;
}
void A() {
std::cout << "In Base func A " << __FUNCSIG__ << std::endl;
}
};
class Derived : public Base {
public:
Derived() {
std::cout << "In Derived Constr: " << __FUNCSIG__ << std::endl;
}
~Derived() {
std::cout << "In Derived Destr: " << __FUNCSIG__ << std::endl;
}
void B() {
std::cout << "In Derived func B " << __FUNCSIG__ << std::endl;
}
};
void test(Base* b) {
Derived* d = static_cast<Derived*>(b);
d->A();
d->B(); // How is this valid??
}
int main() {
Base *b = new Derived();
std::cout << "In main" << std::endl;
b->A();
std::cout << __LINE__ << std::endl;
Base *bb = new Base();
std::cout << __LINE__ << std::endl;
test(bb);
delete b;
delete bb;
}
我不确定,d->B()
行为何以及如何工作?即使指针被类型转换为 Derived class,但 Base class 对象本身不应在内存中具有该函数。
无效。这是未定义的行为。
问题是编译器允许您编写这样的代码。如果指向的对象实际上是 Derived
,则从 Base*
转换为 Derived*
将是有效的。由您作为程序员来确保它是有效的。
在C++中有很多情况你可以像这样搬起石头砸自己的脚。它是语言的一部分。
越界访问、取消引用悬挂 pointers/references 和无效强制转换,仅举几个最常见的例子。
当对象实际上不是该派生类型时,static_cast
到派生 class 是未定义的行为。但是未定义的行为意味着任何事情都可能发生,包括看似有效。 (或者今天似乎工作,然后在最糟糕的时间失败。)
官方从C++语言的角度解释到此为止。
但至于为什么这可能适用于典型的真实编译器和计算机:成员函数的代码实际上并未存储在对象内部,因为那会占用很多字节。对于非虚函数,对象内部甚至没有任何指向该函数的指针或类似的东西。相反,编译器将像非成员函数一样实现函数 Derived::B
:
void __mangled_Derived_B(Derived const* this) { /*...*/ }
然后每次调用B
函数时,它都会传递正确的指针成为“this
”参数。
在您的示例中,Derived::B
实际上根本没有使用 this
,甚至没有隐式使用,因此不太可能出现问题。但如果它试图使用 Derived
的数据成员,事情就会变得更加危险,可能会导致奇怪的结果、对其他对象的更改或崩溃。
I am not sure, why & how the line b->B() works? [..] the Base class object itself should not have that function in memory
你说得对!它没有 工作!
(嗯,函数没有存储 "in memory",但是…)
调用无效。 static_cast
表示 "I promise that this Base*
points to a Derived
"。这个承诺被打破了。
程序有未定义的行为。这在实践中可能意味着事情 "appear" 可以工作,特别是如果没有成员变量被不存在的函数触及...