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.

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. Commented Mar 28, 2022 at 6:47
  • @user17732522 it is, yes, well spotted. I've corrected it. Commented Mar 28, 2022 at 6: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. Commented Mar 28, 2022 at 6: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. Commented Mar 28, 2022 at 6:53
  • 1
    @vkn I'd just like to point out that, since A doesn't have a virtual destructor, having a unique_ptr<A> point to a B is risky all by itself: the moment B needs to do some non-trivial destruction (e.g. has a std::string member), the behavior of deleting through the A is undefined. Also, don't juggle unique ptrs around. Grab the inner raw and cast that. Commented Mar 28, 2022 at 7:07

0

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.