2012-01-29 5 views
17

Возможно ли инициализировать ссылочный элемент NULL в C++?
Я пытаюсь что-то вроде этого:Инициализация ссылки на член в NULL в C++

class BigClass 
{ 
private: 
    Object m_inner; 
public: 
    const Object& ReadOnly; 
    BigClass() : ReadOnly(NULL) 
    { 
    Do stuff. 
    } 
}; 

Я знаю, что могу это сделать, если я инициализировать «ReadOnly» к реальной ссылки объекта, но когда я хочу поставить там «NULL», я получаю ошибку:

"cannot convert from 'int' to 'const Object &'

Как это решить?

+6

Цель ссылки - сделать это невозможным. Вместо этого используйте обычный указатель. –

+0

Вы можете это сделать { const Object & ReadOnly = \ * (Object \ *) NULL; } Но его бешено. Препроцессор просто удаляет & и * * – Justin

+0

@Justin. «Препроцессор просто удаляет« и »и« _ _ »ерунда – curiousguy

ответ

23

Нет, ссылки не могут быть NULL в C++.

Возможные решения включают в себя:

  • с помощью указателя вместо ссылки.
  • с манекеном Object экземпляр, который может использоваться для обозначения «нет объекта».

[1] Из C++11 standard:

[dcl.ref] [...] a null reference cannot exist in a well-defined program, because the only way to create such a reference would be to bind it to the “object” obtained by dereferencing a null pointer, which causes undefined behavior.

+0

@Magnus: Да, не делайте, это неопределенное поведение. – Xeo

+0

Используйте указатель 'const'. – curiousguy

+0

Нет, это неправильно! – wandalen

9

Вы не можете "решить" это. Используйте указатель, если хотите, чтобы этот член не указывал ни на что.

Ссылки должны быть инициализированы реальным объектом, они не могут «указывать в никуда».

+0

Или еще лучше использовать интеллектуальный указатель. – Lalaland

+4

@EthanSteinberg: зависит. Умные указатели обычно связаны с владением. Иногда вы просто хотите указать на что-то, не требуя права собственности. Конечно, вы можете использовать слабый указатель, но для этого требуется выделить объект в куче: нет объекта, выделенного стекю, никакого атрибута большего объекта и т. Д. ... * Умные указатели ** НЕ ** панацея *. –

1

Используйте указатель: - const Объект * pReadOnly;

5

Это можно сделать, но это почти наверняка очень плохая идея. Способ сделать это - разыменовать подходящий типизированный указатель NULL, который уже показывает, что это плохая идея: вы приходите к неопределенному поведению в этот момент, который, однако, обычно имеет тенденцию «работать».

В ссылках на C++ всегда ссылаются на фактический объект. Это отличается от других языков программирования, где «ссылки» на самом деле эквивалентны указателям в C++ (обычно без таких вещей, как арифметика указателя). То, что вы, вероятно, на самом деле хотите (вы, к сожалению, не сказать, что вы пытаетесь достичь его, но на вопрос о решении проблемы, которая, вероятно, является частью ошибочного подхода) является использование указателя вместо:

Object const* const readOnly; 
BigClass(): readOnly(0) {} 
+0

Мой любимый ответ. Мне просто пришлось отлаживать сложный класс и требовать вызова одной функции с определенным объектом. 0 ссылается на все ссылки, как описано, построено obj, игнорируется ссылки, называется функция, исправлена ​​проблема, расстегнуто все. Очевидно, не то, что вы хотите делать надолго. – Cookie

1

Пришло полезно при написании модульных тестов. То есть только место должно быть сделано, но там, это очень полезно.

Bar& bar(*static_cast<Bar*>(0)); 
MockClass mock; // derives from RealClass 
mock.foo(bar); 

Здесь я тестирую код, использующий MockClass, сам не MockClass.

Это не панацея, но это может помочь. Кроме того, GoogleMock может быть вашим другом, если вы издеваетесь над «конкретными» классами.

struct Bar; 
struct RealClass { 
    int& x_; 
    double& y_; 
    RealClass(int& x, double& y) :x_(x), y_(y) {} 
    virtual void foo(Bar&); 
}; 
struct MockClass: public RealClass { 
    MockClass(): RealClass(*(int*)0, *(double*)0) {} 
    MOCK_METHOD1(foo, void(Bar&)); 
}; 
+0

Проголосовавшие: попробуйте это * без *, используя ссылку на NULL. Очень сложно! В случае, если это не очевидно, мы стремимся проверить код, который использует «RealClass» и который вызывает 'foo()' на этом 'RealClass'. Мы вводим как экземпляры «RealClass», так и «Bar». 'MockClass' нужно вызвать конструктор' RealClass', но базовые данные никогда не нужны. Это действительный прецедент, поэтому прекратите голосование. – cdunn2001

+0

Если вам нужно написать такие тесты, я думаю, что у вас серьезная проблема с дизайном. – Nax

+1

Это называется устаревшим кодом, мой друг. – cdunn2001