2014-05-06 3 views
0

Я всегда работал с указателями и избегал ссылок, потому что я не понимал, как работать с ними очень хорошо. Сегодня я работал над небольшим проектом и решил использовать ссылки вместо этого и столкнулся с каким-то поведением. Я не уверен, как работать. В принципе у меня есть завод (завод), который создает либо объект типа В или С, оба из которых являются производными от А.Сохранение объекта производного класса в ссылке на базовый класс

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; 
} 

Проблема возникает, когда я пытаюсь сделать следующее

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 

Когда я проверяю отладчик, нет признаков var2 в a после второго вызова create. Я понимаю его, потому что я использую ссылку на базовый тип C, и только часть A C хранится в контейнере, но есть ли обходной путь? Я знаю, что я могу просто переключить A на A *, но мне интересно, есть ли решение, основанное на указателе.

TL; DR Есть ли способ сохранить объект производного класса в ссылке базового класса без использования указателей?

ответ

0

Я чувствую себя вынужденным указать, что ссылка типа T логически эквивалентна T * const. Так что технически вы не можете обойтись с помощью указателей.

Чтобы ответить на ваш вопрос, абсолютно невозможно сохранить производный класс в ссылке на базовый класс. Проблема в том, что у A, B и C есть потенциально разностные размеры. Вот одно решение:

#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; 
    } 
}; 

Вызывается как:

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

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

Что будет печатать: B: 0 C: 1, 2

К сожалению, это не представляется возможным выделить A и затем назначьте ему B или C позже, так как их размеры не совпадают. Вы либо должны использовать ссылку/указатель с динамическим распределением, либо знать тип раньше времени.

+0

Я бы не сказал, что ссылка * синтаксически эквивалентна * указателю const; в конце концов, вам все равно нужно разыменовать указатель, но не ссылку, и это отражено в синтаксисе. – Brian

+0

Вы правы. Я изменил его на логически, а не синтаксически. Благодарю. –

+0

Спасибо за ответ. Будет ли мне все еще нужно вручную удалить что-либо, если я использую это решение? – inzombiak

Смежные вопросы