如果派生 class 包含额外的方法和成员,static_cast 可以从基 class 到派生 class 吗?
Can static_cast be done from base class to derived class if derived class contains additional methods and members?
假设我们有class A和B如下:
class A
{
private:
int a;
public:
void seta(int a_)
{
a=a_;
}
int geta()
{
return a;
}
};
class B: public A
{
private:
int b;
public:
int getb()
{
return b;
}
void setb()
{
b=geta()+1;
}
};
假设我在函数中编写了这样的代码:
A* a=new A();
a->seta(5);
B* b=static_cast<B*>(a);
b->setb();
cout<<b->getb()<<" and "<<b->geta()<<endl;
这段代码可以编译运行,但我不明白为什么?如果 a
是指向 A
class 的指针并且在分配期间仅保留 class A
成员的内存(在运行时),为什么在静态转换之后似乎这个对象实际上是实例class B
。这样操作安全吗?
[expr.static.cast]/11,强调我的:
A prvalue of type “pointer to cv1 B
”, where B
is a class type, can be converted to a prvalue of type “pointer to cv2 D
”, where D
is a class derived (Clause 10) from B
, if cv2 is the same cv-qualification as, or greater cv-qualification than, cv1. If B
is a virtual base class of D
or a base class of a virtual base class of D
, or if no valid standard conversion from “pointer to D
” to “pointer to B
” exists (4.11), the program is ill-formed. The null pointer value (4.11) is converted to the null pointer value of the destination type. If the prvalue of type “pointer to cv1 B
” points to a B
that is actually a subobject of an object of type D
, the resulting pointer points to the enclosing object of type D
. Otherwise, the behavior is undefined.
这样做并不安全。
下面的代码演示了为什么
#include <iostream>
using namespace std;
class A
{
private:
int a;
public:
void seta(int a_) {
a=a_;
cout << "seta to: " << a << endl;
}
int geta() {
return a;
}
};
class B: public A
{
private:
int b;
public:
int getb() {
return b;
}
void setb() {
b=geta()+1;
cout << "setb to: " << b << endl;
}
};
int main() {
A as[2];
A* a1=as;
A* a2=&as[1];
a1->seta(5);
a2->seta(4);
cout << "a1: "
<< a1->geta()
<< endl;
cout << "a2: "
<< a2->geta()
<< endl;
B* b=static_cast<B*>(a1);
b->setb();
a2->seta(3);
cout << "b->geta(): "
<< b->geta()
<<" and b->getb(): "
<< b->getb()
<< endl;
size_t sizeofa(sizeof(A));
cout << "sizeofa: "
<< sizeofa
<< endl;
size_t sizeofb(sizeof(B));
cout << "sizeofb: "
<< sizeofb
<< endl;
}
输出是
seta to: 5
seta to: 4
a1: 5
a2: 4
setb to: 6
seta to: 3
b->geta(): 5 and b->getb(): 3
sizeofa: 4
sizeofb: 8
假设我们有class A和B如下:
class A
{
private:
int a;
public:
void seta(int a_)
{
a=a_;
}
int geta()
{
return a;
}
};
class B: public A
{
private:
int b;
public:
int getb()
{
return b;
}
void setb()
{
b=geta()+1;
}
};
假设我在函数中编写了这样的代码:
A* a=new A();
a->seta(5);
B* b=static_cast<B*>(a);
b->setb();
cout<<b->getb()<<" and "<<b->geta()<<endl;
这段代码可以编译运行,但我不明白为什么?如果 a
是指向 A
class 的指针并且在分配期间仅保留 class A
成员的内存(在运行时),为什么在静态转换之后似乎这个对象实际上是实例class B
。这样操作安全吗?
[expr.static.cast]/11,强调我的:
A prvalue of type “pointer to cv1
B
”, whereB
is a class type, can be converted to a prvalue of type “pointer to cv2D
”, whereD
is a class derived (Clause 10) fromB
, if cv2 is the same cv-qualification as, or greater cv-qualification than, cv1. IfB
is a virtual base class ofD
or a base class of a virtual base class ofD
, or if no valid standard conversion from “pointer toD
” to “pointer toB
” exists (4.11), the program is ill-formed. The null pointer value (4.11) is converted to the null pointer value of the destination type. If the prvalue of type “pointer to cv1B
” points to aB
that is actually a subobject of an object of typeD
, the resulting pointer points to the enclosing object of typeD
. Otherwise, the behavior is undefined.
这样做并不安全。 下面的代码演示了为什么
#include <iostream>
using namespace std;
class A
{
private:
int a;
public:
void seta(int a_) {
a=a_;
cout << "seta to: " << a << endl;
}
int geta() {
return a;
}
};
class B: public A
{
private:
int b;
public:
int getb() {
return b;
}
void setb() {
b=geta()+1;
cout << "setb to: " << b << endl;
}
};
int main() {
A as[2];
A* a1=as;
A* a2=&as[1];
a1->seta(5);
a2->seta(4);
cout << "a1: "
<< a1->geta()
<< endl;
cout << "a2: "
<< a2->geta()
<< endl;
B* b=static_cast<B*>(a1);
b->setb();
a2->seta(3);
cout << "b->geta(): "
<< b->geta()
<<" and b->getb(): "
<< b->getb()
<< endl;
size_t sizeofa(sizeof(A));
cout << "sizeofa: "
<< sizeofa
<< endl;
size_t sizeofb(sizeof(B));
cout << "sizeofb: "
<< sizeofb
<< endl;
}
输出是
seta to: 5
seta to: 4
a1: 5
a2: 4
setb to: 6
seta to: 3
b->geta(): 5 and b->getb(): 3
sizeofa: 4
sizeofb: 8