在C ++中的函数调用内完成实际的转换是否有效?

时间:2012-01-24 18:30:53

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

我的代码:

#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类,但它仍然调用派生类print!

有人可以为我阐明这一点。

6 个答案:

答案 0 :(得分:6)

  

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

我认为你的意思是“调用派生类打印”,因为那就是发生的事情。

这是虚拟功能的重点;无论用于调用函数的引用或指针的类型(即“静态类型”)如何,都选择与对象的实际类型相关联的最终超控(即“动态类型”)。因此选择了B::print,因为bp仍然指向B的实例。

如果您想强制拨打A::print,可以执行以下操作:

pb->A::print()

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

答案 1 :(得分:3)

您已A::print()成为virtual function

,已明确要求此行为

答案 2 :(得分:2)

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

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

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

答案 3 :(得分:1)

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

此行为是预期且正确的。

此外,

(*a).print();

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

答案 4 :(得分:1)

我无法解决问题所在......第一个是print类型A的实际对象上的print,其他所有对象都是B的调用B对象(直接或通过指针),因此它会调用print的{​​{1}}。

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

这就是virtual功能的工作方式。

答案 5 :(得分:0)

它没有调用基类打印,它在最后一次调用时调用派生类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并且保留了多态行为。