Średnik po nawiasach klamrowych deklaracji klasy

82

W klasach C ++, dlaczego średnik po nawiasie zamykającym? Regularnie o tym zapominam i dostaję błędy kompilatora, a co za tym idzie tracę czas. Wydaje mi się to trochę zbyteczne, co raczej nie ma miejsca. Czy ludzie naprawdę robią takie rzeczy jak:

class MyClass
{
.
.
.
} MyInstance;

Rozumiem to z punktu widzenia zgodności z C dla struktur i wyliczeń, ale ponieważ klasy nie są częścią języka C, wydaje mi się, że przede wszystkim chodzi o zachowanie spójności między podobnymi konstrukcjami deklaracji.

To, czego szukałem, było bardziej związane z racjonalnością projektu, a nie z możliwością zmiany czegokolwiek, chociaż dobre IDE do uzupełniania kodu może to uwięzić przed kompilacją.

SmacL
źródło
4
To może pomóc: cpptalk.net/…
Michael Haren
@Michael, dzięki za link. Z historycznego punktu widzenia ma to sens, a jeśli C ++ zezwala na wszystkie gramatyki języka C, a klasy C ++ są równoznaczne ze strukturami, na końcu klasy pozostaje niezbędny średnik.
SmacL
3
@Brian, tak poważne pytanie. Doskonale zdaję sobie sprawę, że muszę z tym żyć, ale ciekawi mnie uzasadnienie projektu i wdrożenia.
SmacL
OK, ale być może powinieneś zmodyfikować swoje pytanie, aby uwzględnić pożądane uzasadnienie projektu. W obecnej sytuacji zachęca ludzi do zadawania pytań typu „dlaczego aparat ortodontyczny”? :) Możesz być zainteresowany lekturą Stroustrup's Design & Evolution of C ++, chociaż obejmuje ona ważniejsze sprawy niż średniki na końcu zajęć.
Brian Neal
@Brian, w porządku, i to była granica, czy to wiki, czy nie. Pytanie zostało zadane po pominięciu średnika w regularnie używanym nagłówku w dużej kompilacji. Kosztowało mnie to pół godziny, stąd wizyta w SO. Pytanie zredagowane zgodnie z twoją sugestią.
SmacL

Odpowiedzi:

47

Średnik po nawiasie zamykającym w deklaracji typu jest wymagany przez język. Tak było od najwcześniejszych wersji C.

I tak, ludzie rzeczywiście składają deklarację, którą właśnie tam umieściłeś. Jest to przydatne do tworzenia określonych typów wewnątrz metod.

void Example() {
  struct { int x; } s1;
  s1.x = 42;

  struct ADifferentType { int x; };
}

W tym przypadku myślę, że jest jasne, dlaczego potrzebne są średniki. Nie jestem pewien, dlaczego jest to potrzebne w bardziej ogólnym przypadku deklarowania w pliku nagłówkowym. Moje przypuszczenie jest to, że historyczne i zostało zrobione, aby pisać kompilator łatwiejsze.

JaredPar
źródło
Dlaczego nie mogę po prostu utworzyć typu z określonym zakresem bez określenia MyInstance? Wydaje się to dziwne, gdy łączysz dwie czynności: deklarowanie nowego typu i deklarowanie nowej zmiennej.
Mykola Golubyev
@Mykola możesz zrobić jedno i drugie. Zobacz przykład, który dodałem
JaredPar
71

Wydaje się, że link udostępniony przez @MichaelHaren zawiera główną przyczynę . Średnik (jak wskazywali inni) jest dziedziczony po C. Ale to nie wyjaśnia, dlaczego C użył go w pierwszej kolejności. Dyskusja zawiera tę perełkę przykładu:

struct fred { int x; long y; }; 
main() 
{ 
  return 0; 
} 

Starsze wersje języka C miały niejawny typ zwracany przez funkcję, chyba że zadeklarowano inaczej. Jeśli pominiemy ;na końcu definicji struktury, nie tylko definiujemy nowy typ fred, ale także deklarujemy, że main()zwróci wystąpienie fred. Oznacza to, że kod zostanie przeanalizowany w następujący sposób:

struct fred { int x; long y; } main()
{ 
  return 0; /* invalid return type, expected fred type */
} 
Nathan
źródło
1
Tak, niejawny typ powrotu int spowodowałby wszystko tutaj. Niezły klejnot
Gaspa79
17

Wydaje mi się, że to dlatego, że klasy są deklaracjami, nawet jeśli potrzebują nawiasów klamrowych do grupowania. I tak, istnieje historyczny argument, że skoro w C możesz to zrobić

struct
{
  float x;
  float y;
} point;

w C ++ powinieneś być w stanie zrobić podobną rzecz, sensowne jest, aby classdeklaracja zachowywała się w ten sam sposób.

rozwijać
źródło
11

To jest skrót od

class MyClass
{
.
.
.
};

// instance declaration
MyClass MyInstance;  // semicolon here

Średnik po nawiasach klamrowych w deklaracji klasy jest właściwie przesadą, ale tak definiuje się C ++. Średnik po deklaracji zmiennej jest zawsze potrzebny i ma sens.

Stefana Steineggera
źródło
1
Czy więc C ++ wymaga średnika po każdej deklaracji?
Loai Nagati
1
Zauważ, że w ten sposób nie możesz stworzyć obiektu klasy anonimowej, podczas gdy możesz w drugą stronę.
Kevin,
5

Nie korzystam z takich deklaracji

class MyClass
{
.
.
.
} MyInstance;

Ale w tym przypadku mogę zrozumieć, dlaczego jest tam średnik.
Ponieważ jest jakint a; - deklaracja zmiennej.

Prawdopodobnie dla spójności, ponieważ można pominąć średnik „MyInstance”, pozostaje tam.

Mykoła Golubyev
źródło
3

Jest potrzebny po a structze względu na kompatybilność i jak chcesz to:

struct MyStruct { ... };
class  MyClass  { ... }    //inconsistency
Zifre
źródło
1
Ale co z tym namespace myNamespace { ... } // inconsistent but valid?
Chris K
3

W C / C ++; jest zakończeniem instrukcji. Wszystkie instrukcje są zakończone; aby uniknąć niejednoznaczności (i uprościć analizowanie). Gramatyka jest pod tym względem spójna. Mimo że deklaracja klasy (lub jakikolwiek blok w tym przypadku) jest długa na wiele wierszy i jest oddzielona {}, to nadal jest po prostu instrukcją ({} jest częścią instrukcji), dlatego musi zostać zakończona; (; Nie jest separatorem / ogranicznikiem)

W twoim przykładzie

class MyClass{...} MyInstance;

jest kompletnym stwierdzeniem. W jednej instrukcji można zdefiniować wiele instancji zadeklarowanej klasy

class MyClass{...} MyInstance1, MyInstance2;

Jest to całkowicie zgodne z deklarowaniem wielu wystąpień typu pierwotnego w jednej instrukcji:

int a, b, c;

Powodem, dla którego rzadko spotyka się takie określenie klasy i instancji, czy instancja może być tylko? być zmienną globalną i tak naprawdę nie często chcesz obiektów globalnych, chyba że są to statyczne i / lub zwykłe struktury starych danych.

Roger Nelson
źródło
2
Ale definicja funkcji też jest instrukcją, ale bez średników.
Jiapeng Zhang