上投真的是选角吗?

Is upcasting really a casting?

提问人:roi_saumon 提问时间:3/29/2023 最后编辑:roi_saumon 更新时间:3/29/2023 访问量:138

问:

我对 c++ 中的术语 upcast 感到困惑(例如这里)。真的是选角吗?例如,当我将 an 转换为 时,我希望转换类型的行为与 .但是,如果我将派生类向上转换为基类,则似乎强制转换的对象的行为与基类的对象不完全相同,如以下代码所示:intdoubledouble

class Base {
public:
    virtual void print() { cout << "base" << endl; }
};

class Derived :public Base {
public:
    void print() { cout << "derived" << endl; }

};

void main()
{
    // Upcasting
    Derived d;
    Base* pBase = &d;
    
    // test
    Base b;
    Base* pBase2 = &b;

    if (dynamic_cast<Derived*>(pBase));
    {
        cout << "1st upcasting ok" << endl;
    }

    if (dynamic_cast<Derived*>(pBase2))
    {
        cout << "2nd ucasting ok" << endl;
    }
}

输出:

1st upcasting ok
C++ 继承 转换 多态性

评论

3赞 molbdnilo 3/29/2023
任何显式转换都是强制转换。但这些都是向下转换,从基本类型到派生类型。你投射的是指针,而不是它们指向的对象。
5赞 Some programmer dude 3/29/2023
dynamic_cast<Derived*>(pBase2)失败,因为不指向对象。这就是 .pBase2Deriveddynamic_cast
2赞 molbdnilo 3/29/2023
我建议你买一本好书。(这是你发现的一个非常糟糕的页面。
1赞 john 3/29/2023
我不确定您如何认为这是将派生类转换为基类。它显然是另一条路。dynamic_cast<Derived*>(pBase)
1赞 Sam Varshavchik 3/29/2023
“如果我将派生类向上转换为基类”——这不是所示代码的作用。它尝试以完全相反的方向将指向基类的指针转换为指向派生类的指针。又投了一票,选出一本好的C++教科书。

答:

2赞 Cole nelson 3/29/2023 #1

你提出了一个好的观点。在 C++ 中,从技术上讲,上转换不是与将 int 转换为双精度值相同意义上的强制转换操作,因为不会发生对象的实际转换。

当派生类对象被上行转换为基类指针时,派生类对象将被视为基类的对象。实际对象仍然是派生类对象,但指向该对象的指针可以被视为基类指针,只允许访问基类的成员。

在您的示例中,向上转换的对象只能访问 Base 类成员,即使它实际上是 Derived 类的对象。对 upcast 对象调用的 print 函数将调用 Base 类的 print 函数,因为这是基类中定义的函数的版本。但是,如果在 Base 类中将 print 函数声明为虚拟函数,并在 Derived 类中重写,则如果该对象实际上是 Derived 对象,则将调用 Derived 类的 print 函数,即使它被上调到 Base 指针也是如此。

因此,虽然从技术上讲,上转换不是与类型转换相同意义上的强制转换操作,但它是将派生类对象视为 C++ 中基类对象的常用方法。

评论

0赞 roi_saumon 3/29/2023
谢谢。“指向该对象的指针可以被视为基类指针”,这就是所谓的切片吗?这通常是通过操作虚拟表或虚拟指针在后台完成的吗?
1赞 Eljay 3/29/2023
这就是所谓的切片吗? ,切片就像.这通常是通过操作虚拟表或虚拟指针在后台完成的吗? 不,RTTI 数据结构是 const;为了解决问题,可以遍历它们,但不会修改或操纵它们。Base b = d;dynamic_cast
0赞 Pete Becker 3/30/2023
嗯,为了明确说明“向上转换”在 C++ 中做什么或不做什么,你必须严格定义它,而不仅仅是用模糊的例子挥手。我当然希望将派生类型的对象“向上转换”到基本类型的对象将生成该对象的新副本,而没有对“向上转换”进行一些真正不正当的定义。而且,通常,您不能强制转换“派生类对象......到基类指针”。这个答案有一定的道理,但它被含糊不清和草率的措辞所掩盖。
0赞 Cole nelson 3/30/2023
@PeteBecker对不起,我认为这是清晰而直接的。
0赞 roi_saumon 3/30/2023
我不得不思考一会儿,现在我是这样理解的:如果我们定义一个基类和一个派生类,我会想象计算机表示的方式是将派生类的特定信息附加到基类的代码中。因此,当执行 时,指向一个对象,但由于指针具有类型,我们只能从中访问特定于的部分。然后,如果我们做 or ,casted 仍然指向 a,但由于指针类型是 ,它可以访问 的其余部分。ABBA* a = new BaBAAB* casted = static_cast<B*>(a)B* casted = dynamic_cast<B*>(a)B*B
1赞 Swift - Friday Pie 3/29/2023 #2

Upcast 并不是严格意义上的 C++ 术语。 on a pointer 不会创建新对象。dynamic_cast

在第一种情况下,你有类类型的对象,即基类之一。如果将其地址分配给指向 的指针,则仍具有相同的对象。因为派生类是动态类型,而它的静态类型是 。您需要正确获取指向动态类型的指针。DerivedBaseBasepBaseBasedynamic_cast

在第二种情况下,静态和动态类型是相同的。您没有 的对象。 返回 null 指针。Deriveddynamic_cast