samuelnj
samuelnj

Reputation: 1637

Initializing member class with derived class

So I'm trying to find the best practice way to have member classes be constructed to on of their derived classes.

struct A {
    int a = 0
}

struct B : struct A {
    int b = 0;
}
class ContainingClassA {
    ContainingClassA() : member_A(){}

    virtual A get() {
        return member_A;
    }

    A member_A;
}

class ContainingClassB : public ContainingClassA {
    ContainingClassB(){}

    virtual B get() override{
        return member_A;
    }
}

Is there a way of initializing member_A in class ContainingClassB such that it is of type B? I've seen perhaps adding a contructor to ContainingClassA in order to initialize member_A. I know i could just declare a B member_B variable in ContainingClassB and return it, but since B is derived from A it seems like I could somehow store it in the inherited variable member_A...

Upvotes: 0

Views: 97

Answers (2)

rustyx
rustyx

Reputation: 85541

Is there a way of initializing member_A in class ContainingClassB such that it is of type B?

No. member_A is a member of ContainingClassA. ContainingClassB uses the same member_A from its parent class, ContainingClassA. You can't change the layout of the parent class.

Also you can't change the declaration of a virtual function (with a few exceptions). In other words, you can't override A get() with B get().

You could change get() to return a reference instead, then it will be possible to override A& get() with B& get() (as A& and B& are covariant types).

But first you need to split the solution up into an "interface" and two "implementations" for A and B:

#include <iostream>

struct A {
    int a = 0;
};

struct B : public A {
    int b = 1;
};

class ContainingClassBase {
public:
    virtual const A& get() = 0;
};

class ContainingClassA : public ContainingClassBase {
    A member_A;
public:
    virtual const A& get() override { return member_A; }
};

class ContainingClassB : public ContainingClassBase {
    B member_B;
public:
    virtual const B& get() override { return member_B; }
};

int main() {
    ContainingClassA a;
    ContainingClassB b;
    std::cout << a.get().a << std::endl;
    std::cout << b.get().b << std::endl;
}

Note also that a solution with allocating A separately and storing a pointer to it isn't very efficient because it's hard to avoid allocating a spurious A while constructing ContainingClassB (the constructor of ContainingClassA will still be invoked first).

Upvotes: 2

tuple_cat
tuple_cat

Reputation: 1340

You could use templates to be able to choose the type of the variable. Something like this:

#include <iostream>

struct A {
  int a = 0;
};

struct B : A
{
  int b = 0;
};

template<typename T>
class ContainingClassA
{
 public:
  ContainingClassA() : member_A(){}

  virtual T get() {
    return member_A;
  }

  T member_A;
};

class ContainingClassB : public ContainingClassA<B>
{
 public:
  ContainingClassB() { }

  virtual B get() override
  {
    return member_A;
  }
};

int main()
{
  ContainingClassB cb;
  std::cout << cb.get().a;
  std::cout << std::endl;
  std::cout << cb.get().b;
  return 0;
}

Upvotes: -1

Related Questions