2009-04-30 342 views

回答

12

因爲聲明一個類型,它的大小需要知道。您可以轉發聲明指向該類型的指針,或者typedef指向該類型的指針。

如果你真的想,你可以使用pimpl成語來保持包含。但是如果你想使用類型而不是指針,編譯器必須知道它的大小。

編輯:j_random_hacker增加了一個重要的先決條件這個答案,基本上是大小必須知道使用類型,但可以進行預先聲明,如果我們只需要知道存在類型,在爲了創建類型的指針或引用。由於OP沒有顯示代碼,但抱怨說它不會編譯,我假設(可能是正確的)OP正在嘗試使用類型,而不僅僅是指它。

+30

嗯,類類型的前置聲明沒有他們的大小的知識聲明這些類型。另外,除了能夠定義指向這些不完整類型的指針和引用之外,還可以聲明(但未定義)函數,它們接受參數和/或返回這些類型的值。 – 2009-04-30 07:47:44

+3

對不起,我認爲這不是一個好的假設。這個答案就在這一點上。 typedef是前向聲明的例子。 – Cookie 2011-07-22 16:27:09

143

你可以做forward forward typedef。但要做到

typedef A B; 

必須先向前聲明A

class A; 

typedef A B; 
+8

最後+1,因爲雖然你在技術上不能「轉發typedef」(即你不能寫「typedef A;」),但你幾乎可以肯定地完成OP使用上述技巧完成的任務。 – 2009-04-30 07:30:20

+8

但請注意,如果typedef發生更改,您可能也會更改所有這些前向聲明,如果舊的和新的typedef使用具有相同接口的類型,則可能會錯過。 – math 2011-01-27 16:34:54

15

在C++(而不是普通的C),這是完全合法的typedef定義一個類型的兩倍,因此只要這兩個定義是完全相同:

// foo.h 
struct A{}; 
typedef A *PA; 

// bar.h 
struct A; // forward declare A 
typedef A *PA; 
void func(PA x); 

// baz.cc 
#include "bar.h" 
#include "foo.h" 
// We've now included the definition for PA twice, but it's ok since they're the same 
... 
A x; 
func(&x); 
41

對於那些你喜歡我,誰正在尋找轉發聲明使用typede定義的C型結構男,在一些C++代碼,我發現,去如下的解決方案......

// a.h 
typedef struct _bah { 
    int a; 
    int b; 
} bah; 

// b.h 
struct _bah; 
typedef _bah bah; 

class foo { 
    foo(bah * b); 
    foo(bah b); 
    bah * mBah; 
}; 

// b.cpp 
#include "b.h" 
#include "a.h" 

foo::foo(bah * b) { 
    mBah = b; 
} 

foo::foo(bah b) { 
    mBah = &b; 
} 
10

要「FWD聲明的typedef」你需要FWD聲明一個類或結構,然後你可以的typedef聲明的類型。編譯器可以接受多個相同的typedef。

長型:

class MyClass; 
typedef MyClass myclass_t; 

簡稱:

typedef class MyClass myclass_t; 
6

使用前置聲明的完整#include!而非可能只有當你打算使用該類型本身(在這個文件的作用域中),而是指向它的指針或引用。

要使用類型本身,編譯器必須知道它的大小 - 因此必須看到它的完整聲明 - 因此需要完整的#include

但是,無論指針的大小如何,指針或引用的大小都是編譯器已知的,所以前向聲明就足夠了 - 它聲明瞭一個類型標識符名稱。

有趣的是,使用指針或引用classstruct類型時,編譯器可以處理不完全類型節省您需要轉發聲明指針對象類型以及:

// header.h 

// Look Ma! No forward declarations! 
typedef class A* APtr; // class A is an incomplete type - no fwd. decl. anywhere 
typedef class A& ARef; 

typedef struct B* BPtr; // struct B is an incomplete type - no fwd. decl. anywhere 
typedef struct B& BRef; 

// Using the name without the class/struct specifier requires fwd. decl. the type itself.  
class C;   // fwd. decl. type 
typedef C* CPtr; // no class/struct specifier 
typedef C& CRef; // no class/struct specifier 

struct D;  // fwd. decl. type 
typedef D* DPtr; // no class/struct specifier 
typedef D& DRef; // no class/struct specifier 
1

我有同樣的問題,不想在不同的文件類型定義多亂七八糟的,所以我繼承解決它:

是:

class BurstBoss { 

public: 

    typedef std::pair<Ogre::ParticleSystem*, bool> ParticleSystem; // removed this with... 

做:

class ParticleSystem : public std::pair<Ogre::ParticleSystem*, bool> 
{ 

public: 

    ParticleSystem(Ogre::ParticleSystem* system, bool enabled) : std::pair<Ogre::ParticleSystem*, bool>(system, enabled) { 
    }; 
}; 

工作就像一個魅力。當然,我不得不從

BurstBoss::ParticleSystem 

改變任何引用只是

ParticleSystem 
0

正如比爾Kotsias指出,唯一合理的方式,讓您點的typedef細節私人和轉發聲明它們是與繼承。不過,你可以用C++ 11做得更好。試想一下:

// LibraryPublicHeader.h 

class Implementation; 

class Library 
{ 
... 
private: 
    Implementation* impl; 
}; 
// LibraryPrivateImplementation.cpp 

// This annoyingly does not work: 
// 
//  typedef std::shared_ptr<Foo> Implementation; 

// However this does, and is almost as good. 
class Implementation : public std::shared_ptr<Foo> 
{ 
public: 
    // C++11 allows us to easily copy all the constructors. 
    using shared_ptr::shared_ptr; 
};