2

I'm having a problem initializing a shared_ptr member of a class I'm working on.

I have two classes, A and B:

class A {
  int _x;
  int _y;

  public:
    A(int, int);
};

A::A(int x, int y) {
  _x = x;
  _y = y;
}

class B : public A {
  std::shared_ptr<A> _a;

  public:
    B(std::shared_ptr<A>);
};

B::B(std::shared_ptr<A> a) : _a(a) {}

int main() {
  std::shared_ptr<A> a = std::make_shared<A>(1, 2);

  B b(a);

  return 0;
}

I just want class B to hold a std::shared_ptr to an instance of class A. However, I'm getting the error no matching function for call to A::A() in B's constructor.

I'm confused because I thought the point of the initializer list is to avoid implicitly calling the default constructor for member variables, but it still seems to be trying to call A's default constructor.

Any explanation is appreciated, thanks.

edit: after more messing around, it seems like it complies properly if B does not inherit from A. Still unsure why inheriting from A results in A's default constructor being called from B's constructor.

6
  • 1
    The default constructor of A is implicitly called in the constructor of B: B::B(std::shared_ptr<A> a) : _a(a) {}. Because B inherits from A a constructor of A has to be called when B is constructed. Commented Jul 27, 2020 at 5:11
  • 3
    Why do you want B to inherit from A and have a shared_ptr to A at the same time? Commented Jul 27, 2020 at 5:12
  • When you inherit from a class, every object of the new class contains an object of the superclass. class B : A means that each B contains an A. You need to initialize that object somehow. If you don't initialize it in the member initializer list (you aren't) then it defaults to using the default constructor, which doesn't exist. Therefore B must be rejected. Commented Jul 27, 2020 at 5:15
  • If you just want B to hold a shared_ptr to A, why is B derived from A which makes it do more than just hold a shared_ptr? Commented Jul 27, 2020 at 5:23
  • @LouisGo that's what the OP already figured out: it seems like it complies properly if B does not inherit from A Commented Jul 27, 2020 at 5:25

2 Answers 2

2

Since B is derived from A, every B is an A. That means to construct a B, you must also construct an A. However, you do not tell B's constructor how to construct an A, so the default constructor is used.

If you want B to be derived from A and only hold a shared_ptr to A, then A must not do anything you don't want B to do. Here, A has _x and _y.

It's not clear what you really want, but perhaps you want some other base class that both A and B derive from that only has what both A and B should have.

The classic example of inheritance in C++ is something like Instrument being the base class that has members like Play with derived classes like Trumpet and Clarinet having the thing that makes some particular instrument a trumpet. Only what is common to Trumpets and Clarinets should be in Instrument.

Sign up to request clarification or add additional context in comments.

1 Comment

thanks for the answer! to give more detail on the purpose of both A and B: I'm currently learning about the decorator design pattern. In this example, B was a base decorator class, while A was functioning as a concrete class to be decorated. I ended up splitting A into two classes, one abstract base class and one concrete implementation ("plain", or undecorated) class, and have the decorator inherit from the abstract base class only. I fixed my compiler error, now I'm just focusing on not introducing any antipatterns :) thanks again
2

When you call B b(a);, you construct a B object using the constructor B::B(std::shared_ptr<A> a).

The issue is in your definition of this constructor. B inherits from A, meaning that B is not just a B, but instead is really an A and B stacked on top of each other. A is the base class, so it is on the bottom. So when you try to construct a B object, the code must first construct the A object at the bottom/base to form the foundation for the B object to exist on. That means that you actually have to tell the code how to construct the A object.

Because you defined a constructor for A that takes two int variables, the compiler does not generate a default constructor for A. Therefore, you must explicitly write out how A should be constructed within B. Constructing the A object can be done in the initializer list of the B object's constructor:

B::B(std::shared_ptr<A> a) : A(0,0), _a(a) {}

2 Comments

"Because you defined a destructor for A that takes two int variables", is destructor typo for constructor?
@LouisGo Yes, thank you! I've corrected the typo :)

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.