代码之家  ›  专栏  ›  技术社区  ›  Pardeep

使用取消引用对象调用虚拟函数

  •  6
  • Pardeep  · 技术社区  · 14 年前

    我有一个指向派生类对象的基类指针。我打电话来 foo() 在下面的代码中使用两种不同的方法。为什么 Derived::foo() 第一次打电话?不应该 (*obj).foo() 呼叫 Base::foo() 函数是否已取消引用?

        class Base
        {
        public:
            Base() {}
            virtual void foo() { std::cout << "Base::foo() called" << std::endl; }
            virtual ~Base() {};
        };
    
        class Derived: public Base
        {
        public:
            Derived() : Base() {}
            virtual void foo() {  std::cout << "Derived::foo() called" << std::endl; }
            virtual ~Derived() {};
        };
    
        int main() {
            Base* obj = new Derived();
       // SCENARIO 1
            (*obj).foo();
    // SCENARIO 2
            Base obj1 = *obj;
            obj1.foo();
    
            return 0;
        }
    
    8 回复  |  直到 10 年前
        1
  •  15
  •   Community c0D3l0g1c    7 年前
    // SCENARIO 1
    (*obj).foo();
    

    注意

    1. obj is a misnomer here, since it doesn't refer to an object, but to a 指针 ,
    2. (*ptr).foo() 只是一种迂回的方式 ptr->foo() .

    *ptr 不会导致对象,但会导致 参考 Base& 对象。以及通过 参考 接受动态调度,就像通过指针调用一样。

    // SCENARIO 2
    Base obj1 = *ptr;
    obj1.foo();
    

    你要做的是通过 slicing :它只是具有 *PTR . 你想要的是:

    Base& ref = *ptr;
    ref.foo();
    
        2
  •  3
  •   bdonlan    14 年前

    场景2创建了一个全新的基本类型的对象。因此,当我们这样做的时候 obj1.foo() ,对象根本不是派生的;我们无法调用派生函数。

    然而,在场景1中,对象实际上是派生的实例,我们通过基指针访问它。这正是虚拟函数设计的情况;使用派生类的实现。

        3
  •  1
  •   Peter Milley    14 年前

    如果您稍微考虑一下实现,这会有所帮助。在第二个场景中,您实际上正在创建一个新的基本类型的对象,该对象将随新的虚拟函数表一起提供。但在第一种情况下 *obj 将“指向”或更确切地说是引用仍然具有派生类型对象的虚拟函数表的对象。

        4
  •  1
  •   Community c0D3l0g1c    7 年前

    作为其他答案的补充。

    场景2中发生的事情的技术术语是对象切片。

    这是维基百科的词条:

    http://en.wikipedia.org/wiki/Object_slicing

    还有一个关于对象切片的stackoverflow的问题:

    What is object slicing?

        5
  •  1
  •   max    10 年前

    第一种情况是 foo() 由于上述明显原因将被呼叫。除了其他答案 *(*Obj).func()* *Obj->func()* .

    第二种情况是类的新对象 Base 正在通过复制构造函数实例化,因为它是 基地 类对象,它将调用 基地 的类版本 英尺() .

        6
  •  0
  •   Ben Voigt    14 年前

    多态性对引用(指针取消引用的结果)的作用与对指针的作用相同。

        7
  •  0
  •   ckv    14 年前

    你所说的“因为它已经被取消引用”是什么意思?

    基类指针obj指向派生类对象,由于您声明了函数foo()virtual,因此将调用派生类foo()。

        8
  •  0
  •   AnT stands with Russia    14 年前

    (这个问题很奇怪。我宁愿有人问为什么在第二种情况下 Derived::foo 不被调用。

    在C++语言中,调用虚拟函数的哪一个版本完全独立于什么和什么没有被“去引用”。取消引用没有任何区别。唯一重要的是 动态类型 调用中使用的对象。

    在第一种情况下 派生: 调用的原因是 *obj 对象是 Derived .

    在第二种情况下,动态类型 obj1 Base 所以 Base::foo 被称为。

    In other words, everything works as expected. 这让人奇怪,你问了你一个问题。是什么让你期望有所不同?