0
#include <iostream>
class FooChild
{
public:
    FooChild(){}
    virtual void doThis() {std::cout << "doThis Parent" << std::endl;}
    virtual bool doThat(int n, double x) { std::cout << "doThat Parent" << std::endl; return false; }
};


class FooFighter
{
public:
    void doSomething(FooChild &fooChild)
    {
        fooChild.doThis();
        fooChild.doThat(4, 5);
    }
    void doSomethingPtr()
    {
        m_child->doThis();
        m_child->doThat(4, 5);
    }
    void doSomethingREF()
    {
        r_child.doThis();
        r_child.doThat(4, 5);
    }
    friend void setChild(FooFighter& obj, FooChild* child);
    friend void setChild(FooFighter& obj, FooChild& child);

private:
    FooChild* m_child;
    FooChild  r_child;
};

void setChild(FooFighter& obj, FooChild* child){
    obj.m_child = child;
}

void setChild(FooFighter& obj, FooChild& child){
    obj.r_child = child;
}

class MockFooChild : public FooChild
{
public:
    void doThis() {std::cout << "doThis Child" << std::endl;}
    bool doThat(int n, double x) { std::cout << "doThat Child" << std::endl; return false; } 
};


int main(){
    
    MockFooChild mockFooChild;
    FooFighter fooFighter;

    setChild(fooFighter, &mockFooChild);
    setChild(fooFighter, mockFooChild);

    std::cout << "Pointer is calling: \n";
    fooFighter.doSomethingPtr();
    std::cout << "Ref is calling: \n";
    fooFighter.doSomethingREF();
    std::cout << "Passing it by ref is calling: \n";
    fooFighter.doSomething(mockFooChild);
}

https://godbolt.org/z/v7GdPWr5e

I expected the following output:

Pointer is calling: 
doThis Child
doThat Child
Ref is calling: 
doThis Child
doThat Child
Passing it by ref is calling: 
doThis Child
doThat Child

but I am instead seeing:

Pointer is calling: 
doThis Child
doThat Child
Ref is calling: 
doThis Parent
doThat Parent
Passing it by ref is calling: 
doThis Child
doThat Child

Why is MockFooChild's function not getting called and the parent class' function is being used instead?

Marek R
  • 32,568
  • 6
  • 55
  • 140
  • you do not have a reference there. You have a value! Fixed version https://godbolt.org/z/Mn9eee9r3 – Marek R Oct 26 '22 at 16:24
  • 1
    Since rChild is NOT a reference, but an actual FooChild OBJECT, the assignment of the reference to the rChild object is being "sliced". See https://stackoverflow.com/questions/2432683/what-does-slicing-mean-in-c – franji1 Oct 26 '22 at 16:26
  • Simple typo. `FooChild r_child;` should be `FooChild& r_child;`. – YSC Oct 26 '22 at 16:28
  • @YSC that won't work, because `setChild()` won't be able to re-bind the `r_child` reference to refer to the input `child` object. Once a reference is bound, it can't be changed. So, in this situation, only a `FooChild*` pointer will work. – Remy Lebeau Oct 26 '22 at 16:52
  • Any way to avoid a using a pointer. I am trying to inject a mock using a friend to replace an existing FooChild member, and to use a pointer, I'd have to refactor a lot. @RemyLebeau – Micheal Jokim Oct 26 '22 at 17:08
  • @MichealJokim sorry, but a pointer is the only way to go in this situation. A reference simply can't be rebound to a different object, but a pointer can be. If you want to use a reference as a class member, the only place you can bind it is in the constructor's member initialization list. – Remy Lebeau Oct 26 '22 at 17:45
  • @Remy indeed. Better closed as dup of "what is slicing" I agree. – YSC Oct 26 '22 at 21:42

0 Answers0