1

Here is a little challenge.

I have a base class X (nonvirtual) and a child class Y that adds some dependency-specific implementation.

I also have a pure-virtual base A that defines an interface in terms of X, and class B that adds some dependency-specific implementation and relies on Y features.

class X {
public:
  //rule of 0 applies
  double getSomething() {return something;}
  void setSomething(const double s) {something = s;}

private:
  double something{0};
};

class Y : public X {
public:
  //rule of 0 applies
  int getSomethingElse() {return somethingElse;}
  void setSomethingElse(const int s) {somethingElse = s;}
};

The fun begins here!

class A {
public:
  virtual void foo(std::unique_ptr<X> basePtr) = 0;
  virtual ~A() = default;
protected:
  A() = default;
}

class B : public A {
public:
  void foo(std::unique_ptr<Y> derivedPtr) {
    std::cout << "Something " + derivedPtr->getSomething() + " SomethingElse " + derivedPtr->getSomethingElse();
  }
}

The error occurs when attempting to std::make_shared<B>():

invalid new-expression of abstract class type 'B' {...}

... note: because the following virtual functions are pure within `B`:
  class B : public A {
        ^
... note: virtual void foo(std::unique_ptr<A>) = 0;
                       ^~~

I can think of one solution, that would be to have the B::foo signature in terms of X and to cast the argument to a std::unique_ptr<Y> in its definition, but I'm wondering if something cleaner exists.

vkn
  • 191
  • 12
  • 1
    I think it have no way, due to A::foo and B::foo is difference. B::foo don't override A::foo. lets cast as you said. – long.kl Mar 28 '22 at 06:47
  • @user17732522 it is, yes, well spotted. I've corrected it. – vkn Mar 28 '22 at 06:49
  • @long.kl This is what I'm afraid of, yes. The casting adds a whole lot of extra mess to each function, but it may be the only way to get this to work. A shame that smart pointers have these extra hoops to jump through - doing it with raws would be a lot less messy. – vkn Mar 28 '22 at 06:50
  • I don't really understand the interface. If `foo` is virtual in `A`, then I ought to be able to call `foo` on any `A*` without having to know what the derived class is. But you want to require different arguments to be passed depending on the derived class. – user17732522 Mar 28 '22 at 06:53
  • @vkn No, it wouldn't be less messy. It would also still be wrong according to the Liskov Substitution Principle - if `B::foo` requires the passed argument to be a `Y`, then it is not a correct implementation of the abstract `A::foo`. – Sebastian Redl Mar 28 '22 at 06:53
  • Does this answer your question? [How to override a pure virtual function using a subclass reference in the overriden function](https://stackoverflow.com/questions/59388766/how-to-override-a-pure-virtual-function-using-a-subclass-reference-in-the-overri) – moooeeeep Mar 28 '22 at 06:53
  • @vkn I think at `A::foo ( std::unique_ptr x) `mean you want to use `x::` by `Y class `rather than using a new method like `Y::getSomethingElse` – long.kl Mar 28 '22 at 06:56
  • @SebastianRedl Apologies, I wasn't clear - less messy as in rather than having several lines of casting, releasing and resetting the unique_ptrs, just have the `B` interface in terms of `X` and have a one-line cast at the top of `B::foo`. @moooeeeep That could work, as well as https://stackoverflow.com/a/17417920 . As @long.kl points out, this doesn't look like it's going to happen without a bit of juggling. Thanks for the suggestions! – vkn Mar 28 '22 at 07:04
  • 1
  • Great comment @SebastianRedl, many thanks. Unless I'm mistaken, `A` does have a virtual destructor - unless there is some odd behaviour on `default` I am unaware of? Did you mean `X`? The naming of these is terrible, I tried to come up with something but naming is hard. Yes, the inner raw would be casted in any tidy handling of this, it seems. – vkn Mar 28 '22 at 07:12
  • @vkn Yes, I meant `X` and `Y`, got them mixed up. – Sebastian Redl Mar 28 '22 at 07:13
  • I do not understand the question. What should `B::foo(std::unique_ptr)` do with a pointer to `X` that __is not__ `Y`? `foo(std::unique_ptr` and `foo(std::unique_ptr)` are very different functions. – KamilCuk Mar 28 '22 at 16:58

0 Answers0