Neden çift sütun kullanarak bir ad alanındaki bir sınıfı ileri bildiremiyorum?


164
class Namespace::Class;

Bunu neden yapmam gerekiyor ?:

namespace Namespace {
    class Class;
}

Derleyici VC ++ 8.0 kullanarak:

hata C2653: 'Ad alanı': bir sınıf veya ad alanı adı değil

Burada sorun derleyici Namespacebir sınıf ya da bir ad alanı olup olmadığını söyleyemiyorum olduğunu varsayalım ? Peki bu sadece ileri bir beyan olduğu için neden önemli?

Bazı ad alanlarında tanımlanan bir sınıfı iletmenin başka bir yolu var mı? Yukarıdaki sözdizimi, ad alanını "yeniden açıyorum" ve tanımını genişletiyormuşum gibi geliyor. Ya Classaslında tanımlanmamışsa Namespace? Bu bir noktada hataya neden olur mu?


44
Buradaki tüm cevaplara katılmama izin verin ve bunun sadece dilin bir tasarım hatası olduğunu söyleyeyim. Daha iyi düşünebilirlerdi.
Pavel Radzivilovsky

Bu, bunun neden C ++ 'da (öznel olan) yasadışı olduğu konusunu tartışıyor ve tartışmacı görünüyor. Kapatmak için oylama.
David Thornley

7
Nasıl derleyici içinde olduğunu bilmek gerekiyordu bir ad tanımlayıcı yerine sınıf adıdır? A::BA
David R Tribble

@STingRaySC: Tartışma özneldir, çünkü C ++ 'ın bunu neden yaptığını açık bir cevap yoktur, bu yüzden spekülasyon yapıyoruz. (Soru, daha önce yanıtlanmış olan objektif cevapları olan bazı soruları olan bir av tüfeği sorusudur.) Bu noktada, argüman izlerine karşı duyarlı hale geldim ve Pavel ile bunun C ++ 'ın bir yanlış özelliği olduğu konusundaki anlaşmanız yeterlidir. NamespaceBir sınıf veya ad alanı neden önemli olduğu sorusuyla hiç sorun yaşamadım . Sadece sözdizimi üzerinde bir dil alev savaşı akla gelme olasılığının ipucu yakınında bir yere gitmeyin.
David Thornley

Yanıtlar:


85

Çünkü yapamazsın. C ++ dilinde tam nitelikli adlar yalnızca var olan (yani daha önce bildirilen) varlıkları ifade etmek için kullanılır . Yeni tanıtmak için kullanılamazlar varlıkları .

Ve olan Yeni varlık beyan etmek ad "yeniden açılması" aslında. Eğer sınıfClass daha sonra farklı ad alanının bir üyesi olarak tanımlanırsa - burada bildirdiğiniz sınıfla hiçbir ilgisi olmayan tamamen farklı bir sınıftır.

Önceden bildirilen sınıfı tanımlama noktasına geldiğinizde, ad alanını tekrar "yeniden açmanıza" gerek yoktur. Genel ad alanında (veya alanınızı çevreleyen herhangi bir ad alanında Namespace)

class Namespace::Class {
  /* whatever */
};

Daha önce ad alanında bildirilmiş bir objeye başvurduğunuzdan Namespace, nitelikli ad kullanabilirsiniz Namespace::Class.


10
@STingRaySC: İç içe bir sınıfı iletmenin tek yolu, bildirimi ekteki sınıfın tanımına yerleştirmektir. Ve gerçekten de içine alan sınıfı, kapalı sınıfın tanımından önce iletmenin bir yolu yoktur.
AnT

@STingRaySC: Yuvalanmış bir sınıf ileri bildirilebilir - cevabımı görün.
John Dibling

8
@John Dibling: İç içe sınıf , başka bir sınıfın içinde bildirilen bir sınıftır. Hemen bir ad alanının içinde bildirilen bir sınıf, iç içe bir sınıf değildir. Cevabınızda yaşlı sınıflarla ilgili hiçbir şey yok.
AnT

198

Doğru cevaplar alıyorsunuz, sadece yeniden yazmayı deneyelim:

class Namespace::Class;

Bunu neden yapmam gerekiyor?

Bunu yapmak zorundasınız çünkü terim Namespace::Classderleyiciye şunu söylüyor:

... Tamam, derleyici. Git Ad Alanı adlı ad alanını bulun ve bunun içinde Sınıf adlı sınıfa bakın.

Ancak derleyici, neden bahsettiğinizi bilmiyor çünkü adında bir ad alanı bilmiyor Namespace. Şu şekilde adlandırılmış bir ad alanı olsa bile Namespace:

namespace Namespace
{
};

class Namespace::Class;

yine de işe yaramaz, çünkü o ad alanının dışından bir ad alanındaki bir sınıfı bildiremezsiniz. İsim alanında olmalısınız.

Böylece, aslında bir ad alanı içindeki bir sınıfı ileri bildirebilirsiniz. Sadece bunu yap:

namespace Namespace
{
    class Class;
};

39
Diğer tüm cevaplar benim için kafa karıştırıcıydı ama bu "bir isim alanının içindeki bir sınıfı o isim alanının dışından ilan edemezsin. İsim alanında olmalısın." hatırlamak için çok yararlı bir ipucu oldu.
dashesy

22

Sanırım aynı nedenden ötürü iç içe ad alanlarını şöyle bildiremezsiniz:

namespace Company::Communications::Sockets {
}

ve bunu yapmak zorundasınız:

namespace Company {
  namespace Communications {
    namespace Sockets {
    }
  }
}

1
Bu aslında neden yapamayacağınızı açıklayan bir cevap değildir.
StarPilot

6
Bu benim zamanımdan büyük tasarruf sağlayan bir cevap
Kadir Erdem Demir

17
C ++ 17 bunu ekler.
rparolin

Burada hepsinin isim alanı olduğunu biliyorsunuz. Ancak Company :: Communications :: Socket sınıfıyla, Communications'ın bir ad alanı mı yoksa sınıf mı (soket yuvalanmış sınıf olduğu) bilmiyorsunuz.
Lothar

12

İleri bildirilen bir değişkenin türünün gerçekte ne olduğu açık değildir. Ön deklarasyon class Namespace::Class;,

namespace Namespace {
  class Class;
}

veya

class Namespace {
public:
  class Class;
};


6
Bunun en iyi cevaplardan biri olduğunu düşünüyorum, çünkü bunun neden derleyicinin kendisi tarafından kolayca belirlenemediğini cevaplıyor.
Devolus

1

Onlara izin vermemenin mantığı hakkında çok sayıda mükemmel cevap var. Sadece sıkıcı standardı hüküm vermek istiyorum, özellikle yasaklar. Bu, C ++ 17 (n4659) için geçerlidir.

Söz konusu paragraf [class.name] / 2'dir :

Yalnızca sınıf anahtarı tanımlayıcısından oluşan bir bildiri ; ya geçerli kapsamdaki adın bir yeniden ifadesi ya da sınıf adı olarak tanımlayıcının ileri bir bildirimidir. Sınıf adını geçerli kapsama sokar.

Yukarıdakiler, ileri bir bildirimi (veya bir sınıfın yeniden düzenlenmesini) neyin oluşturduğunu tanımlar. Esas olarak, biri olmalıdır class identifier;, struct identifier;ya da union identifier;burada tanıtıcısında yaygın sözcük tanımı [lex.name] :

identifier:
  identifier-nondigit
  identifier identifier-nondigit
  identifier digit
identifier-nondigit:
  nondigit
  universal-character-name
nondigit: one of
  a b c d e f g h i j k l m
  n o p q r s t u v w x y z
  A B C D E F G H I J K L M
  N O P Q R S T U V W X Y Z _
digit: one of
  0 1 2 3 4 5 6 7 8 9

[a-zA-Z_][a-zA-Z0-9_]*Hepimiz aşina olduğumuz ortak planın üretilmesidir . Gördüğünüz gibi, bu bir tanımlayıcı olmadığından class foo::bar;geçerli bir ileri bildirim olmaktan kaçınır foo::bar. Tamamen nitelikli bir isim, farklı bir şey.

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.