2016-08-08 2 views
3

Я бы хотел использовать полиморфизм со ссылками, без оператора new. Существует один BaseClass, который имеет некоторый (в данном случае один) виртуальный метод. И подклассы реализуют его.Используйте полиморфизм со ссылками. Недопустимая инициализация ссылки не const

Я создал фабричную функцию, которая создает соответствующий экземпляр. Но я получаю эту ошибку:

invalid initialization of non-const reference of type 'BaseClass&' from an rvalue of type 'SubOne' 

Код является:

#include <iostream> 

class BaseClass { 
public: 
    virtual void run() = 0; 
}; 

class SubOne : public BaseClass { 
public: 
    virtual void run() override { 
     std::cout << "I am SubOne!" << std::endl; 
    } 
}; 

class SubTwo : public BaseClass { 
public: 
    virtual void run() override { 
     std::cout << "I am SubTwo!" << std::endl; 
    } 
}; 

BaseClass& baseFactory(int num) { 

    switch(num) { 

     case 1: 
      return SubOne(); 

     case 2: 
     default: 
      return SubTwo(); 

    } 

} 

void executer(BaseClass& base) { 

    // code... 

    base.run(); 

    // code... 

} 

int main() { 

    BaseClass& base = baseFactory(1); 

    // code... 

    executer(base); 

    return 0; 
} 
+4

Это наименьшее из ваших забот. Возврат ссылки на локальный объект приводит к неопределенному поведению, если используется ссылка. – juanchopanza

+1

У вас не может быть объекта без динамического распределения памяти. Ссылки не являются волшебными. 'std :: shared_ptr' есть, используйте их. –

ответ

2

Вы не можете вернуть локально созданный объект из функции, которая возвращает ссылку:

BaseClass& baseFactory(int num) { 
    ... 
    return SubOne(); // Not allowed 
} 

Это происходит потому, локальный объект выходит за пределы области действия, как только функция завершается, и вы получаете ссылку на подвеску.

Вы должны изменить свою функцию, чтобы возвращать динамически выделенный объект, и хранить его в смарт-указатель:

BaseClass* baseFactory(int num) { 
    ... 
    return new SubOne(); 
} 

unique_ptr<BaseClass> dyn { baseFactory(1) }; 
+0

Кроме того, если есть причина, по которой вы хотите избежать нового оператора, вы можете предоставить пользовательский распределитель, я думаю, что он сможет дать лучший ответ, чем это нам нужно знать * почему * вы не хотите используйте кучу. –

1

Если изменить тип возвращаемого baseFactory к const, вы обратите внимание на следующее предупреждение появляется (Внимание: видно here)

In function 'const BaseClass& baseFactory(int)':

27:27: warning: returning reference to temporary [-Wreturn-local-addr]

31:27: warning: returning reference to temporary [-Wreturn-local-addr]

Как вы можете видеть, вы не можете вернуть реальную ссылку на временную переменную, потому что, как говорит предупреждение, что IS временный. Вы не можете вернуть ссылку на то, чего не существует, ака-то болтая ссылка. К сожалению, единственный способ сделать это, является использование указателей, иначе:

BaseClass* baseFactory(int num) { 

    switch(num) { 

     case 1: 
      return new SubOne(); 

     case 2: 
     default: 
      return new SubTwo(); 

    } 

} 

Проблема с этим состоит в том, что функция вызова, здесь главный, приходится иметь дело с очисткой, или вы получите утечку памяти. Или, как @dasblinkenlight включил в свой ответ, вы можете использовать RAII (R esource cquisition I сек I nitialization), и держать класс в смарт-указатель, где деструктор умный указатель удалит объект.