Search code examples
c++referenceoverloadingvirtual-functionsoverload-resolution

Overloading resolution of C++ virtual functions - references vs pointers


I'm puzzled by A behavior in C++ overloading resolution. I have 2 classes, A and B, with A<:B. A has a virtual function f and B is supposed to override that function.

However, virtual functions don't seem to work as virtual when I invoke them using references. At first I thought this was due to the objects being allocated on the stack instead of the heap, but now I see that this weird behavior happens even when I use references to objects allocated on the heap.

What's the explanation for this?

#include<iostream>

using namespace std;

class A{
public:
    virtual void foo(){ cout << "A::foo" << endl; }
};

class B : public A{
public:
    virtual void foo(){ cout << "B::foo" << endl; }
};

void test_pt(A* pt){
    cout << "test_pt " << (int)pt << " ";
    pt->foo();
}

void test_ref(A ref){
    cout << "test_ref " << (int)&ref << " ";
    ref.foo();
}

int main(int argc, char* argv[]){
    // pointers to objects allocated on heap
    A* heap_pt_a = new A;
    B* heap_pt_b = new B;

    // virtual functions work as intended
    test_pt(heap_pt_a); // test_pt 4975912 A::foo
    test_pt(heap_pt_b); // test_pt 4975960 B::foo

    // references to objects allocated on heap
    A heap_ref_a = *heap_pt_a;
    B heap_ref_b = *heap_pt_b;

    // virtual functions work as non-virtual
    test_ref(stack_ref_a); // test_ref 1571400 A::foo
    test_ref(stack_ref_b); // test_ref 1571400 A::foo

    // references to objects allocated on stack
    A stack_ref_a;
    B stack_ref_b;

    // virtual functions work as non-virtual
    test_ref(stack_ref_a); // test_ref 1571400 A::foo
    test_ref(stack_ref_b); // test_ref 1571400 A::foo

    // references to stack used as pointers to stack
    // virtual functions work as intended
    test_pt(&stack_ref_a); // test_pt 1571724 A::foo
    test_pt(&stack_ref_b); // test_pt 1571712 B::foo

    return 0;
}

Solution

  • The function test_ref takes an A by value. This is not passing by reference. The argument ref in that function is a local object which was copied from an object in the calling function. (If it was copied from a B this is called slicing).

    Passing by reference would be:

    void test_ref(A &ref)
    

    Whether the objects are "stack" or "heap" makes no difference.

    Similarly, your comment is wrong in:

    // references to objects allocated on stack
    A heap_ref_a = *heap_pt_a;
    

    Here, heap_ref_a is a copy of the object pointed to by heap_pt_a. It is not a reference, they are now two distinct objects. A reference would be:

    A &heap_ref_a = *heap_pt_a;