3

I have an abstract base class with one purely virtual method:

class Base
{
public:
    virtual void update() = 0;
};

Is there any way I could create a class that inherits from Base, overrides the update method, but still forces its children to implement an update method? Like this:

class Base2 : public Base
{
public:
    void update() override
    {
        if(bSomeCondition)
        {
            update(); //Calls child's update method
        }
    }
    virtual void update() = 0; // Obviously not like this
};

I know I could create two new purely virtual methods with slightly different names in Base2, and just override those in child classes, but I would really like to keep these method names if that would be possible.

I'm guessing this isn't possible?

JensB
  • 839
  • 4
  • 19
  • Possibly related https://stackoverflow.com/questions/9477581/force-all-classes-to-implement-override-a-pure-virtual-method-in-multi-level – Cortex0101 Jul 01 '21 at 10:48
  • 1
    So, it is possible, but it's unclear what you hope to achieve. When would the intermediate function be called, and why? – Useless Jul 01 '21 at 10:56
  • I suspect you might be better off making a Base0 that both Base and Base2 are child classes that override the function of Base0 – Abel Jul 01 '21 at 11:48
  • The usual approach is to derive classes directly from `Base`, not from `Base2`. In other words, don't derive from concrete (instantiable) classes. C++11 and later, that can be enforced by tagging `Base2` as `final`. – Peter Jul 01 '21 at 12:20
  • *"`// Obviously not like this`"* -- well, obviously the line stating "obviously" is the obvious way to do it. It's the inline definition above the "obviously" line that is obviously the problem. :) *Have I mentioned recently that "obviously" more often qualifies false statements than true ones? Always doubt yourself whenever you find yourself saying something is obvious!* – JaMiT Jul 02 '21 at 02:37
  • @JaMiT Hmm, not sure what you mean. When I try to do it like that, regardless of whether the definition is inline or in a `.cpp` file, it points me to the purely virtual update method and gives me the error `'virtual void Base2::update' cannot be overloaded with 'void Base2::update'` – JensB Jul 02 '21 at 16:12
  • @JensB It works when I do it (and when Yksisarvinen did it), so *obviously* you did something wrong. *(Yes, obviously I am still intentionally over-using the word "obvious".)* – JaMiT Jul 02 '21 at 16:47
  • @JaMiT But Yksisarvinen never did it like that. Look at his answer again. He never overrode the update method and created a new update method in the same class. Frankly, I don't know how having two different methods with the same name and number of arguments could ever work. – JensB Jul 03 '21 at 08:30
  • @JensB What are you talking about? Yksisarvinen did keep the line you marked "Obviously not like this", as that line is the way to do it (changing `virtual` to `override` is merely cosmetic for current purposes). Yksisarvinen did change the inline definition to an out-of-class definition, as the inline definition is the problem. Exactly as I wrote. (Note: the answer was posted before my comment, which is why I did not post an answer. Yksisarvinen did not copy me.) – JaMiT Jul 03 '21 at 15:37
  • @JensB I don't know where you got this idea that there is supposed to be a new update method. I wrote nothing about "override" or "new" -- do a "find in page" to check that. You're apparently (excuse me, *obviously*) reading things that are not there. – JaMiT Jul 03 '21 at 15:41
  • @JaMiT Oh, now I see it. My bad. Apologies if I came off as arrogant, I was just genuinely trying to understand what you meant. Thanks for the help! – JensB Jul 04 '21 at 10:24

2 Answers2

2

You can provide a definition for a pure virtual function, just not inline.

class Base2 : public Base
{
public:
    void update() override = 0;
};

void Base2::update() // Base2 is abstract regardless of this
{
    if(bSomeCondition)
    {
        update(); 
    }
}

However, this is not useful with the current implementation of Base2::update. Because a child class must override it anyway, Base2 version will not be called unless used explicitly:

class Child: public Base2
{
public:
    void update() override
    {
        Base2::update(); //infinite recursion with such implementation
    }
};

// the other way would be to require calling it explicitly at call site

std::unique_ptr<Base2> ptr = std::make_unique<Child>();
ptr->Base2::update(); 

What you should do is to provide an implementation and another pure virtual function (possibly protected) to be called:

class Base2 : public Base
{
public:
    void update() override;

protected:
    virtual void doStuff() = 0;
};

void Base2::update()
{
    if(bSomeCondition)
    {
        doStuff(); //Calls child's update method
    }
}
Yksisarvinen
  • 18,008
  • 2
  • 24
  • 52
  • A child class calling `Base2::update()` (and not `update()`) would not lead to any recursion. – StoryTeller - Unslander Monica Jul 01 '21 at 10:49
  • @StoryTeller-UnslanderMonica Won't it go like: `Child::update()` calls `Base2::update()`, which in turn calls unqualified `update()`, which gets resolved to `Child::update()`, which again calls `Base2::update()`? I think I should illustrate it with code why it's a bad idea maybe. – Yksisarvinen Jul 01 '21 at 10:51
  • 1
    Only because you chose to make an unqualified call in your intermediate pure virtual function. It's not intrinsic to the mechanism though - you could just have logged "don't call this". Admittedly I can't think of a _use_ unless you're trying to avoid crashing when making virtual function calls during destruction. – Useless Jul 01 '21 at 10:55
  • 1
    Ah, the OP's example at a desperate attempt. Yes, that would be infinite. But it reads like a more general problem in your answer. Different functions are indeed the path forward. – StoryTeller - Unslander Monica Jul 01 '21 at 10:55
-1

No, it is not possible and in my opinion it would be very illegible.

slsy
  • 1,257
  • 8
  • 21