1

I have a class that derives from a base class, which has a nested class. I want to override a nested class's member function in my derived class and override a base class's member function. (as shown below)

I found a solution (https://stackoverflow.com/a/11448927/13147242) that works by creating another nested class that inherits from the base class's nested class. But when creating an instance of this new nested class I get another return type, which doesn't help me because the function that I want to override that returns a base's nested class object, but should access the nested's override function.

A code example of that setup looks like this:


class Base {
public:
  class Nested {
    friend class Derived;

  public:
    virtual void funcNested() { std::cout << "funcNested()" << std::endl; }
  };

  virtual Nested funcBase() {
    std::cout << "funcBase()" << std::endl;
    Nested tmp;
    tmp.funcNested();
    return tmp;
  }
};

class Derived : public Base {
public:
  // I want to override this function without creating another nested class that derives from Nested, i.e.
  // void Base::Nested::funcNested() override { /* ... */ }

  // the mentioned solution does it like this:
  class DerivedNested : public Base::Nested {
  public:
    void funcNested() override { std::cout << "override funcNested()" << std::endl; }
  };

  // but then I can't override this function in a way that the nested function is called
  Nested funcBase() override {
    std::cout << "override funcBase()" << std::endl;
    return DerivedNested();
  }
};


int main() {
  Derived derived;
  Base::Nested nested = derived.funcBase();
  nested.funcNested();

  return 0;
}

Then the output here is:

override funcBase()
funcNested()

but I want to have:

override funcBase()
override funcNested()

Is this possible?

fakl
  • 127
  • 7

1 Answers1

1

It appears the issue is that in this line Base::Nested nested = derived.funcBase(); a copy of type Nested is created by a Nested::Nested(Nested&) copy constructor, out of derived object (DerivedNested). Then in nested.funcNested(); line a method is called on that copy object of parent class, thus no dynamic dispatch here.

As described in this answer of the similar question, you should use reference/smart pointer to prevent creating a copy of the base class. Like:

#include <memory>

class Base {
public:
  class Nested {
    friend class Derived;

  public:
    virtual void funcNested() { std::cout << "funcNested()" << std::endl; }
  };

  virtual std::shared_ptr<Nested> funcBase() {
    std::cout << "funcBase()" << std::endl;
    Nested tmp;
    tmp.funcNested();
    return std::make_shared<Nested>(tmp);
  }
};

class Derived : public Base {
public:
  class DerivedNested : public Base::Nested {
  public:
    virtual void funcNested() override { std::cout << "override funcNested()" << std::endl; }
  };

  std::shared_ptr<Nested> funcBase() override {
    std::cout << "override funcBase()" << std::endl;
    DerivedNested tmp;
    tmp.funcNested();
    return std::make_shared<DerivedNested>(tmp);
  }
};

int main() {
    Derived derived; 
    auto nested = derived.funcBase(); 
    nested->funcNested();

    return 0;
}
Renat
  • 7,718
  • 2
  • 20
  • 34
  • Thanks for your reply! Yeah I just tried that myself while waiting for an answer, but this doesn't work for me because it wouldn't allow me to call ```funcNested()``` with the returned instance of ```funcBase()```. i.e. ``` Derived derived; Base::Nested nested = derived.funcBase(); nested.funcNested(); ``` wouldn't call the derived's nested. – fakl Aug 31 '22 at 10:40
  • this produces the output: "override funcBase() override funcNested() funcNested() " – fakl Aug 31 '22 at 10:41
  • instead of "override funcBase() override funcNested() override funcNested() " – fakl Aug 31 '22 at 10:41
  • it appears to be answered here: https://stackoverflow.com/a/1444066/1075282 – Renat Aug 31 '22 at 10:56
  • Thanks! This solves the described problem, but this won't work for my original problem, where the nested class is an ```Iterator``` class and in ```Derived``` I want to override the ```Iterator begin()``` function which has to return a object and not a pointer to an object in order to be able to use range based for loops. The nested class function I want to override would be ```bool Iterator::operator!=()```. – fakl Aug 31 '22 at 11:37
  • The reason for that is that I want to throw an exception in ```begin()``` if the object is in a specific state and reduce the original ```opertator!=```'s runtime by using integer comparison instead of functions that allow comparisons for all types. The reason for that is as follows: My base class is a ```Range``` object which can have any type and basically implements an arithmetic series. The derived class is called ```Index``` which is an arithmetic series with only integer parameters. @Renat – fakl Aug 31 '22 at 11:39
  • @fakl , one possible implementation could be to store in the iterator e.g. a const reference to the collection, implement virtual comparison method in parent and derived collections, then in Iterator::operator!=() proxy call to collection' comparison method. This should call overridden comparison. As a side note because virtual calls more expensive than static ones, and with virtual calls compiler is restricted with optimizations, this could be less performant, so may be consider using templates for polymorphism instead of inheritance, if this would be applicable. – Renat Aug 31 '22 at 13:30