2012-01-29 8 views
17

Czy możliwe jest zainicjowanie elementu referencyjnego na wartość NULL w języku C++?
Próbuję coś takiego:Inicjowanie odniesienia do elementu na NULL w C++

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

wiem, że mogę to zrobić, jeśli zainicjować „tylko do odczytu” do realnego odniesienia do obiektu, ale kiedy chcę, aby umieścić tam „null”, pojawia się błąd:

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

Jak mogę rozwiązać ten problem?

+6

Punkt odniesienia polega na uniemożliwieniu tego. Zamiast tego użyj zwykłego wskaźnika. –

+0

Możesz to zrobić { const Object & ReadOnly = \ * (Object \ *) NULL; } Ale jest fugly. Pre-procesor po prostu usuwa & * i \ * – Justin

+0

@Justin "_Procesor wstępny po prostu usuwa bzdury & i * _". – curiousguy

Odpowiedz

23

Nie, odniesienia nie mogą być NULL w C++.

Możliwe rozwiązania:

  • stosując wskaźnik zamiast odniesienia.
  • z instancją Dummy Object, która może być użyta do wskazania "brak obiektu".

[1] Z 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: Tak, nie rób tego, to niezdefiniowane zachowanie. – Xeo

+0

Użyj wskaźnika 'const'. – curiousguy

+0

Nie, to źle! – wandalen

9

nie można "rozwiązać" ten. Użyj wskaźnika, jeśli chcesz, aby ten członek nie wskazywał niczego.

Referencje muszą być inicjowane do prawdziwego obiektu, nie mogą "wskazywać nigdzie".

+0

Albo jeszcze lepiej, użyj inteligentnego wskaźnika. – Lalaland

+4

@EthanSteinberg: zależy. Inteligentne wskaźniki zazwyczaj wiążą się z własnością. Czasami chcesz wskazać coś bez roszczenia własności. Oczywiście można użyć słabego wskaźnika, ale wymaga to przydzielenia obiektu na stercie: brak przydzielonego obiektu, brak atrybutu większego obiektu itp. * Inteligentne wskaźniki to ** NIE ** panaceum *. –

5

Można to zrobić, ale prawie na pewno jest to bardzo zły pomysł. Aby to zrobić, należy wyłuskać odpowiednio wpisany wskaźnik NULL, który już pokazuje, że jest to zły pomysł: w tym momencie dochodzi do niezdefiniowanego zachowania, które jednak zazwyczaj ma tendencję do "pracy".

W referencjach C++ oznacza się, że zawsze odnoszą się do rzeczywistego obiektu. Różni się to od innych języków programowania, w których "odnośniki" są w rzeczywistości odpowiednikami wskaźników w C++ (zazwyczaj bez takich rzeczy jak arytmetyka wskaźnikowa). Co prawdopodobnie rzeczywiście chcą (ty niestety nie mówią, co staramy się go osiągnąć, ale poprosił o rozwiązanie problemu, który jest prawdopodobnie częścią błędne podejście) jest użycie wskaźnika Zamiast:

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

Moja ulubiona odpowiedź. Właśnie musiałem debugować złożoną klasę i musiałem wywołać pojedynczą funkcję z pewnym obiektem. 0 odnosił się do wszystkich odniesień, jak opisano, konstruował obiekt, ignorował referencje, wywoływał funkcję, naprawiał problem, odpinał wszystko. Oczywiście nie jest to coś, co chcesz robić na stałe. – Cookie

1

Nadszedł przydatne w pisaniu testów jednostkowych. To jest miejsce, które powinno być zrobione, ale jest całkiem pomocne.

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

Tutaj jestem testowania kodu, który wykorzystuje MockClass, sama nie MockClass.

To nie jest panaceum, ale może pomóc. Także, GoogleMock może być twoim przyjacielem, jeśli kpisz z "konkretnych" klas.

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

Down-voters: Spróbuj tego * bez * używając odwołania do NULL. Bardzo trudne! W przypadku, gdy nie jest to oczywiste, staramy się przetestować kod, który używa 'RealClass' i który wywołuje' foo() 'w tym' RealClass'. Wprowadzamy instancje "RealClass" i "Bar". 'MockClass' musi wywoływać konstruktor' RealClass', ale podstawowe dane nigdy nie są potrzebne. Jest to ważny przypadek użycia, więc przestań głosować. – cdunn2001

+0

Jeśli chcesz napisać ten rodzaj testów, myślę, że masz poważny problem z projektowaniem. – Nax

+1

To się nazywa legacy code, przyjacielu. – cdunn2001

Powiązane problemy