【问题标题】:Does casting actually work when done inside a function call in C++?在 C++ 中的函数调用中完成强制转换是否真的有效?
【发布时间】:2012-02-18 00:12:35
【问题描述】:

我的代码:

#include <iostream>

using namespace std;

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

class B : public A
{
public:
    void print(void) { cout << "I am class B" << endl; }
};

void mainprint(A *a)
{
    (*a).print();
}

int main()
{
    A a;
    B b;

    B *bp;
    A *ap;

    ap = &b;

    a.print();
    b.print();
    (*ap).print();

    bp = new B();

    mainprint((A *)bp);

    delete bp;

    return 0;
}

输出:

I am base class
I am class B
I am class B
I am class B

我已经在函数调用中将指针(bp)转换为类A,但它仍然调用派生类打印!!!

谁能帮我解释一下。

【问题讨论】:

    标签: c++ oop casting virtual base-class


    【解决方案1】:

    你期待什么?这就是多态性的工作原理。

    这种行为是预期的并且是正确的。

    还有,

    (*a).print();
    

    不是强制转换,而是取消引用。

    【讨论】:

    • @rashid "我已将指针 (bp) 投射到函数调用 内部 类 A"...
    • 我的意思是 mainprint((A *)bp);如果我有什么困惑,请纠正我。
    • @rashid 哦,好吧,我一定是误会了。
    【解决方案2】:

    它不是调用基类 print,而是在您上次调用时调用派生类 print(我是 B 类),这是正确的行为,因为指针和引用适用于多态性。

    如果你切片你的对象然后调用 print 它确实会打印 A 版本。你不想这样做,幸运的是你没有。

    这将是切片:

    B b;
    A a(b); 
    A a2;
    a2 = b;
    A& a3 = b;
    b.print();
    a.print();
    a2.print();
    a3.print();
    

    你应该得到:

    我是B班 我是基类 我是基类 我是B班

    因为aa2 都是a 类型的对象,即使您已将它们分配给b。 不建议切片,但这是一个常见错误。

    然而,a3 是对 A 类型的对象或其派生对象之一的引用,但实际上是 B 类型的对象 b,并保留了多态行为。

    【讨论】:

      【解决方案3】:

      它是虚函数调度(即运行时多态),按预期工作。

      禁用虚函数调度的一种方法是用类名明确限定函数名,如下所示:

      void mainprint(A *a) 
      { 
        (*a).A::print(); 
      }
      

      【讨论】:

        【解决方案4】:

        我不知道问题出在哪里...第一个是print 类型为A 的实际对象,所有其他都是printB 对象上的调用(直接或通过指针),所以它调用Bprint

        请记住,在函数调用中,您不会将 B 类型的 object 转换为 A 类型的 object(这会导致切片) ,但您只是在投射一个指向它的指针 - 对象本身保持不变,并且由于虚拟调度,即使对象的静态类型是 A *,也会调用正确版本的虚函数。

        virtual 函数就是这样工作的。

        【讨论】:

        • 没问题,我只是想明白!
        • +1 用于确定指向对象的指针和对象本身之间的差异。
        【解决方案5】:

        我已经在函数调用中将指针(bp)转换为类 A,但它仍然调用基类 print!!!

        我假设您的意思是“调用派生类打印”,因为这就是发生的事情。

        这就是虚函数的重点;选择与对象的实际类型(即“动态类型”)关联的最终覆盖,无论用于调用函数的引用或指针的类型(即“静态类型”)。所以选择了B::print,因为bp仍然指向B的一个实例。

        如果你想强制调用A::print,你可以这样做:

        pb->A::print()
        

        或者,如果您根本不想要多态行为,请删除 virtual 规范。

        【讨论】:

          【解决方案6】:

          您已通过将A::print() 设为virtual function 来明确请求该行为。

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 2011-10-13
            • 2013-02-27
            • 2015-06-21
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2015-03-31
            相关资源
            最近更新 更多