gpt4 book ai didi

c++ - 指针向下转换和向上转换的用法区别?

转载 作者:塔克拉玛干 更新时间:2023-11-02 23:14:38 25 4
gpt4 key购买 nike

我想知道当我们使用向下转换和向上转换时,指针转换到底发生了什么。我有两个问题。其中前 2 个是评论。 Q3终于结束了。

#include<iostream>
using namespace std;
class A{
public:
virtual void f()
{
cout<<"A"<<endl;
}
};
class B: public A{
public:
virtual void f()
{
cout<<"B"<<endl;
}
};
int main()
{
A* pa =new A();
B* pb =new B();
A* paUpcast= new B();
/*
Q1:
Is the line above equivalent to the following?
A* paUpcast = (A*) B;
*/
B* pbDowncast=(B*)paUpcast;
/*
Q2:Why we cannot use the following 2 code;
B* pbDowncast=new A();
B* pbDowncast = (B*) pa;
*/
pa->f();
pb->f();
paUpcast->f();
pbDowncast->f();


return 1;
}

问题 3:我想总结一个规则来推断如果我们将虚函数和指针一起使用会发生什么,但我就是想不通。

本来我以为虚函数会把我们带到指针真正指向的地方。因此,当我们输入

A* paUpcast= new B();
paUpcast->f();

如果A.f()是虚函数,第二行会显示“B”,因为paUpcast实际上是指向B对象

但是,当我们输入

B* pbDowncast=(B*)pa;
pbDowncast->f();

并且它会显示“A”而不是“B”,这使得矛盾发生了。

任何人都可以解释或告诉我一些提示吗?非常感谢

最佳答案

我会尝试解释我是如何理解它的。对我有帮助的秘诀是考虑乐高积木。

在您的例子中,我们有两 block 乐高积木,一 block 名为 A,另一 block 名为 B...但想象一下 B piece是两 block 拼接而成的一 block ,其中一 block 是同类型的A:

 A     B
+-+ +-+-+
|a| |a|b|
+-+ +-+-+

然后,您使用指针引用每个乐高积木,但每个积木都有自己的形状,所以,想象一下:

A* pa =new A();
B* pb =new B();
A* paUpcast= new B();

A *pa --> +-+ new A()
|a|
+-+
B* pb --> +-+-+ new B()
|a|b|
+-+-+
A* paUpcast --> +-+-+ new B()
|a|b|
+-+-+

请注意,paUpcast 指针是一个A 类型的指针,但持有一个B 类型的指针,B 片段与 A 片段不同,如您所见,这是一个片段略大于它的基础。

这就是你所说的向上转型,基指针就像一个通配符,可以容纳继承树上向下相关的任何东西。

A* paUpcast= new B();

Is the line above equivalent to the following?

A* paUpcast = (A*) B;

好吧,假设您真的想这样写:A* paUpcast = (A*) new B(); 是的,它是。您创建了 B 类的新实例并将其存储到指向 A 类的指针中,在分配给指针之前转换新实例不会改变它的事实无论如何都会被存储到一个基类指针中。

Why we cannot use the following 2 code;

B* pbDowncast=new A();

B* pbDowncast = (B*) A;

记住乐高积木。在执行 B* pbDowncast=new A() 时会发生什么?:

B* pbDowncast --> +-+ new A()
|a|
+-+

创建一个新的基类实例并将其存储到派生类的指针中,您试图将基类视为派生类,如果您仔细观察乐高积木不合适! A 缺少 extra stuff 必须考虑 B 类型;所有这些东西都“存储”到乐高积木的额外部分,B = 所有 A 东西加上更多东西:

  B
+-+-----------------------------------+
|a|extra stuff that only B pieces have|
+-+-----------------------------------+

如果您尝试调用只有 B 类具有的方法,会发生什么情况?有了 B 指针,您就可以调用所有 B 方法,但是您创建的实例来自 A 类型B 方法,它不是用所有这些额外的东西创建的。

However, when we type

B* pbDowncast=(B*)pa;

pbDowncast->f();

display "A" instead of "B", which make the contradiction happen.

这对我来说并不矛盾,记得乐高积木,pa 指针指向一 block A:

A *pa --> +-+
|a|
+-+

这篇文章缺少所有 B 的东西,事实是缺少在标准上打印 Bf() 方法输出...但它有一个方法 f() 在输出上打印 A

希望对您有所帮助!

编辑:

It seems that you also agree that it is inappropriate to use the downcast isn't it?

不,我不同意。向下转型一点也不不合适,但根据它的用途,它会是不合适的。与所有 C++ 工具一样,向下转型也有实用性和使用范围;所有尊重良好使用的诡计都是适当的。

那么向下转型工具有什么好的用途呢?恕我直言,任何不会破坏代码或程序流程的东西,尽可能保持代码的可读性,并且(对我来说最重要的是)如果程序员知道他在做什么。

向下转换采用可能的继承分支毕竟是一种常见的做法:

A* paUpcast = new B();
static_cast<B*>(paUpcast)->f();

但是用更复杂的继承树会很麻烦:

#include<iostream>
using namespace std;
class A{
public:
virtual void f()
{
cout<<"A"<<endl;
}
};
class B: public A{
public:
virtual void f()
{
cout<<"B"<<endl;
}
};
class C: public A{
public:
virtual void f()
{
cout<<"C"<<endl;
}
};

A* paUpcast = new C();
static_cast<B*>(paUpcast)->f(); // <--- OMG! C isn't B!

要解决这个问题,您可以使用dynamic_cast

A* paUpcast = new C();

if (B* b = dynamic_cast<B*>(paUpcast))
{
b->f();
}

if (C* c = dynamic_cast<C*>(paUpcast))
{
c->f();
}

但是 dynamic_cast 因它的 lack of performance 而广为人知。 ,您可以研究 dynamic_cast 的一些替代方案,例如内部对象标识符或转换运算符,但为了坚持这个问题,如果使用正确,向下转换一点也不坏。

关于c++ - 指针向下转换和向上转换的用法区别?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/12947825/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com