I've always worked with pointers and avoided references because I didn't understand how to work with them very well. Today I was working on a small project and decided to use references instead and ran into some behavior I'm not sure how to work around. Basically I have a factory (Factory) that creates either an object of type B or C, both of which are derived from A.

class Factory
{
public:
    void create(A& container, int a) //This is for creating an object of B
    {
        B result;
        result.Func(a);
        container = result;
    }
    void create(A& container, int a, int b) //This is for creating an object of C
    {
        C result;
        result.Func(a, b);
        container = result;
    }   
}

class A
{
public:
    virtual void Func(int a) //This is used for an object of B
    {
        var1 = a;
    }; 
    virtual void Func(int, int) {}; // This is used for an object of C

private:
    int var1;
}

class B : public A
{
    //Relies of base class Func to set the variable var1;
}

class C : public A
{
public:
    void Func(int a, int b)
    {
        A::Func(int a)
        var2 = a1;
    }

private:
    int var2;
}

The issue arises when I try to do the following

Factory factory;
A a;
factory.create(a, 1); //Works fine because B and A have only 1 variable
factory.create(a, 1, 1); //a only contains A part of C

When I check the debugger, there is no sign of var2 to in a after the 2nd create call. I understand its because I'm using a reference to the base type of C and only the A part of C gets stored in the container, but is there a workaround? I know I can just switch A to A*, but I'm interested if there is a non-pointer based solution.

TL;DR Is there a way to store an object of a derived class in a reference of the base class without using pointers?

有帮助吗?

解决方案

I feel compelled to point out that a reference of type T is logically equivalent to a T * const. So technically, you can't get around using pointers.

To answer your question, it is absolutely possible to store a derived class in a reference to a base class. The issue is that A, B, and C all have potentially difference sizes. Here is one solution:

#include <stdio.h>

class A
{
public:
  virtual void Function()
  {
    printf("A\n");
  }
};

class B : public A
{
public:
  virtual void Function()
  {
    printf("B: %d\n", var1);
  }

  int var1;
};

class C : public A
{
public:
  virtual void Function()
  {
    printf("C: %d, %d\n", var1, var2);
  }

  int var1, var2;
};

class Factory
{
public:
  A & Create(int a)
  {
    B &b = *new B;
    b.var1 = a;
    return b;
  }

  A & Create(int a, int b)
  {
    C &c = *new C;
    c.var1 = a;
    c.var2 = b;
    return c;
  }
};

Called like:

Factory factory;
A &a1 = factory.Create(0);
A &a2 = factory.Create(1, 2); 

a1.Function();
a2.Function();

Which will print: B: 0 C: 1, 2

Unfortunately, it's not possible to allocate an A and then assign a B or C to it later, since their sizes don't match. You either must use a reference/pointer with dynamic allocation, or know the type ahead of time.

许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top