2012-04-27 21 views
9

Przeglądałem go i czytałem wiele postów, ale jest tak wiele różnych odpowiedzi, z których wszystkie mają logiczny sens, że zastanawiałem się, czy ekspert w tej sprawie mógłby zdemistyfikować to pytanie.Konstruktory C++ nie mają typu zwracanego. Właśnie dlaczego?

Niektórzy mówią, że nie ma powrotu, ponieważ nie ma możliwości powrotu - składnia to zabrania - tak, to ma sens, ale wierzę, że wszystkie funkcje muszą coś zwrócić, nie? Inni mówią, że konstruktor sortuje zwracany sam nowo utworzony obiekt, co wydaje się mieć sens, ponieważ operator przypisania jest używany w konstruktorze. Jeszcze inne mają inne interesujące wyjaśnienia.

+0

Z ciekawości, kiedy byłoby użyteczne, a nawet ma sens, aby konstruktor zwrócił coś innego niż obiekt, który konstruuje? – kevin628

+0

AFAIK zwraca nowo utworzony obiekt. –

+4

Kto powiedział, że konstruktor jest funkcją? (Oprócz faktu, że jest to opisane w sekcji Standard o "Special Member Functions") –

Odpowiedz

12

Konstruktory nie są nazywane jak inne funkcje, więc nie zwracają się tak jak inne funkcje. Działają jako efekt uboczny pewnych konstrukcji (obsada, new, definicja zmiennej, lista inicjatora ctor, wartość przekazana, wartość zwracana przez).

8

Konstruktor konstruuje na miejscu, nie ma potrzeby zwracania czegokolwiek.

wierzę, że wszystkie funkcje muszą powrócić coś

void?

+0

Konstruktorzy nie zwracają nawet 'void' (jeśli to ma sens).Nie mają typu zwrotu. –

+1

@DavidHammen To tylko różnica w składni. Deklaracja, że ​​typ zwracany przez funkcję ma być "void", ma to samo znaczenie. – bames53

+0

Czy to tylko różnica w składni? Konstruktor jest funkcją void w tym sensie, że instrukcja return musi być 'return;' w konstruktorze. Jednakże, czyniąc konstruktor niemożliwym do wyłapania i pozostawiając typ nieokreślony, standard wydaje się umożliwiać dostawcy kompilatora, aby konstruktor zwracał coś tak długo, jak działa - jeśli zwraca pustkę. –

1

Konstruktorów, dla których nie ma typu zwrotu - nie ma nawet void - oznacza, że ​​nie można wywołać konstruktora z kodu C++. I o to chodzi. Wywołanie konstruktora nie ma sensu. Nielegalne wywoływanie konstruktora eliminuje możliwość wystąpienia tego rodzaju błędu użytkownika.

Edytuj

Barnes ma rację, że ostateczny powód, dla którego nie można nazwać konstruktorów jest to, że nie mają nazwy. (A nawet to ignoruje, które można wywołać konstruktora pośrednio poprzez umieszczenie nowego.)

Próbując ponownie:

nie można nazwać konstruktorów z kodu C++, ponieważ konstruktorzy nie mają nazwy. Sprawiając, że konstruktory nie mają typu powrotu, programista podkreśla, że ​​konstruktory są bardzo odmiennym rodzajem funkcji niż inne funkcje. To, co faktycznie zwraca konstruktor, jeśli zwraca coś, zależy od dostawcy.

+0

Fakt, że konstruktorzy nie zwracają niczego, nie ma nic wspólnego z tym, czy można wywołać konstruktora. Nie można wywołać konstruktora, ponieważ konstruktory nie mają nazwy i nie ma składni do wywoływania tego. (Tylko obejście, nowe miejsce docelowe). – bames53

10

Konstruktor nie określa typu zwracanego, ponieważ byłby on nadmiarowy: nie istnieje typ inny niż konstruktor, który konstruktor mógłby potencjalnie "zwrócić". Wstawiam "return" w cudzysłowach, ponieważ technicznie konstruktorzy nic nie zwracają: gdy są wywoływani w statycznym kontekście, inicjują instancję w miejscu; gdy są wywoływane w kontekście dynamicznym, to operator new zwraca coś, a nie konstruktor.

+2

a rzecz, która * wygląda * jak wywołanie konstruktora, jest w rzeczywistości rzutem. –

+2

@downvoter proszę wyjaśnić swój głos – dasblinkenlight

1

ale wierzę, że wszystkie funkcje muszą coś zwrócić, nie?

Nie. Co to znaczy zwrócić wartość z funkcji? Cóż, ABI dla implementacji określi, że dla pewnego typu zwracanego funkcja ustawi pewne rejestry, lub trochę pamięci w pewnym przesunięciu od wskaźnika stosu, do wartości, która jest "zwracana" przez funkcję.

Oczywiście rejestry i pamięć istnieją i zawierają dane po wywołaniu konstruktora lub funkcji void, ale język mówi, że te funkcje nic nie zwracają, a zatem ABI nie określa, które rejestry lub pamięć mają szukać, aby znaleźć wartość zwracana. Kod nie może ustawić wartości zwracanej, a kod wywołujący może uzyskać dowolną wartość zwracaną.

Więc nie, funkcje nie muszą zwracać niczego.

2

Zakładając konstruktorzy mogli powrócić coś, to jest problematyczne konsekwencje dla następnego wywołania funkcji:

class Object{ 
    public: 
     bool Object(){ ... }; 
     ... 
}  

SomeFun(Object obj){ ... } 

SomeFun(Object()); 
// Ha! SomeFun jokes on an error about a non-Object argument(of type bool), returned 
// by the anonymous temporary Object() 

zapobieganie powrotowi funkcji konstruktora, ułatwia korzystanie z anonimowych tymczasowych, wraz z wielu innych funkcji C++. Bez takiej zasady, nieszkodliwe sprawozdanie może stać się niejednoznaczne:

Object obj(Object()); 
// How does the variable obj decide which constructor to call, 
// based on its argument type? 
// 
// Does it call: bool Object::Object(Object&) or 
//     Object::Object(bool)(if it exists)? 

Zdolność dla konstruktorów zwrócić wartość, utrudnia tworzenie obiektów - mający pojedynczą jednoznaczną typ, nazwę klasy, w przypadku braku wartości dowolnych powrotów , unika tych problemów.

Czy czytelnicy mogą sugerować dalsze przykłady, w których idiomy C++ są utrudnione przez brak takiej reguły?

+0

ten argument mógłby nam wierzyć, że konstruktor zwracający arbitralne wartości byłby pożądany, gdyby nie pocierał innych ustalonych cech językowych w niewłaściwy sposób ... przeciwnie, konstruktor jest funkcją specjalnego przeznaczenia [używany aby zainicjować obiekty swojej klasy] (http://www2.research.att.com/~bs/glossary.html#Gconstructor) ... zrewidować odpowiedź w tym świetle ... – user1055604

0

Konstruktory domyślnie zwracają wystąpienie samej klasy. Będzie to sprzeczne, jeśli został zaprojektowany, aby zwrócić coś, a programista zwrócił coś zupełnie innego niż sama klasa. Zasadniczo składnia byłaby myląca.

1

Konstruktory są prawdopodobnie złą nazwą. Jest to praktycznie inicjator dla wstępnie skonstruowanych obiektów. Najprostszym sposobem zilustrowania tego jest pseudo-przykład dla równoważnej konstrukcji bez użycia konstruktorów C++.

Z konstruktorów

struct X { 
    int a; 
    X() { 
     a = -5; 
    } 
}; 

int main() { 
    X* x1 = new X(); // X created as a "reference object". 
    X x2;   // X created as a "value object" on the stack. 
    return x1->a - x2.a; 
} 

Bez konstruktorów

struct X { 
    int a; 
    void initialize() { 
     a = -5; 
    } 
    static X* create() { 
     X* res = (X*)malloc(sizeof(X)); 
     res->initialize(); 
     return res; 
    } 
}; 

int main() { 
    X* x1 = X::create(); // New constructed heap-allocated X 
    X x2;    // Stack-allocated X 
    x2.initialize();  // Manually initialized 
    return x1->a - x2.a; 
} 

Teraz, jeśli sobie wyobrazić, że X::initialize w drugim przykładzie miały zostać wykonane, aby wrócić, powiedzmy bool wskazując sukces lub niepowodzenie, byś mieć problem. W wersji main() nieuważny programator może zakończyć się niepowodzeniem, ponieważ nie został poprawnie zainicjowany, co prowadzi do niezdefiniowanego zachowania (zwykle jest to trudna do debugowania awaria, która może nie zostać wykryta przed rozpoczęciem produkcji).

Jest to jeden z głównych powodów, dla których konstruktorzy są wyjątkowi. Jedynymi dwoma sposobami wyjścia z konstruktora są normalne zakończenie lub wyjątek, który następnie musi być obsługiwany przez wywołującego (lub przekazywany na stos). W każdym razie uniemożliwiasz zakończenie niezainicjowanych obiektów.

Na marginesie niezainicjowane obiekty są jedną z najczęstszych przyczyn błędów w C, która nie ma nic, co mogłoby pomóc programistom w ten sposób.

Powiązane problemy