C++中前置声明介绍
前置聲明是指對類、函數、模板或者結構體進行聲明,僅僅是聲明,不包含相關具體的定義。在很多場合我們可以用前置聲明來代替#include語句。
類的前置聲明只是告訴編譯器這是一個類型,但無法告知類型的大小,成員等具體內容。在未提供完整的類之前,不能定義該類的對象,也不能在內聯(lián)成員函數中使用該類的對象。而頭文件則一一告之。
如:class Screen;
前置聲明,也稱前向聲明(forward declaration)。在聲明之后,定義之前,類Screen是個不完整類型(incomplete type),即已知Screen是一個類型,但是不知道包含哪些成員。
不完全類型只能以有限方式使用。不能定義該類型的對象。不完全類型只能用于定義指向該類型的指針及引用,或者用于聲明(而不是定義)使用該類型作為形參類型或返回類型的函數。
可以通過前置聲明配合指針或引用類型聲明來減少編譯依賴。
???????? Never #include a header when a forward declaration will suffice.
???????? 前置聲明的作用:
(1)、可以減少編譯依賴、減少編譯時間(如果頭文件被修改,會導致多次重新編譯);
(2)、可以隱藏細節(jié);
(3)、可以減少類大小(前置聲明會告訴這個類的存在,而不用提供類定義的所有細節(jié));
(4)、減少include,防止類間相互引用形成依賴,造成編譯不通過.
以下是在Google C++風格指南中對前置聲明的介紹:
盡可能地避免使用前置聲明。使用#include 包含需要的頭文件即可。
所謂前置聲明(forward declaration)是類、函數和模板的純粹聲明,沒伴隨著其定義.
優(yōu)點:
(1)、前置聲明能夠節(jié)省編譯時間,多余的 #include 會迫使編譯器展開更多的文件,處理更多的輸入。
(2)、前置聲明能夠節(jié)省不必要的重新編譯的時間。 #include 使代碼因為頭文件中無關的改動而被重新編譯多次。
缺點:
(1)、前置聲明隱藏了依賴關系,頭文件改動時,用戶的代碼會跳過必要的重新編譯過程。
(2)、前置聲明可能會被庫的后續(xù)更改所破壞。前置聲明函數或模板有時會妨礙頭文件開發(fā)者變動其 API.例如擴大形參類型,加個自帶默認參數的模板形參等等。
(3)、前置聲明來自命名空間std:: 的 symbol 時,其行為未定義。
(4)、很難判斷什么時候該用前置聲明,什么時候該用 #include 。極端情況下,用前置聲明代替 includes 甚至都會暗暗地改變代碼的含義.
結論:
(1)、盡量避免前置聲明那些定義在其他項目中的實體.
(2)、函數:總是使用#include.
(3)、類模板:優(yōu)先使用#include.
以下摘自《Using Incomplete(Forward) Declarations》:
An incomplete declaration(an incomplete declaration is often called a forward declaration) is the keyword class or struct followed by the name of a class or structure type.It tells the compiler that the named class or struct type exists, but doesn't say anything at all about the member functions or variables of the class or struct; this omission means that it is a (seriously) incomplete declaration of the type. Since an incomplete declaration doesn't tell the compiler what is in the class or struct, until the compiler gets the complete declaration, it won't be able to compile code that refers to the members of the class or struct, or requires knowing the size of a class or struct object (to know the size requires knowing the types of the member variables).
Use an incomplete declaration in a header file whenever possible. By using an incomplete declaration in a header file, we can eliminate the need to #include the header file for the class or struct, which reduces the coupling, or dependencies,between modules, resulting in faster compilations and easier development. If the .cpp file needs to access the members of the class or struct, it will then #include the header containing the complete declaration.
When will an incomplete declaration work in a header file:
(1)、If the class type X appears only as the type of a parameter or a return type in a function prototype.
class X;
X foo(X x);
(2)、If the class type X is referred to only by pointer (X*) or reference (X&), even as a member variable of a class declared in A.h.
class X;
class A {
/* other members */
private:X* x_ptr;X& x_ref;
};
(3)、If you are using an opaque type X as a member variable of a class declared in A.h.This is a type referred to only through a ?pointer,and whose complete declaration is not supposed to be available, and is not in any header file. Thus an incomplete declaration of the type is the only declaration your code will ever make or need either in A.h or A.cpp.
When will an incomplete declaration not work in a header file:
(1)、If your A.h header file declares a class A in which the incompletely declared type X appears as the type of a member variable.
class X;
class A {
private:X x_member; // error- can't declare a member variable of incomplete type!
};
(2)、If your A.h header file declares a class A in which the incompletely declared type X is abase class (A inherits from X).
class X;
class A : public X { // error - baseclass is incomplete type!
(3)、If you don't actually know the name of the type. You can't forward declare a type unless you know its correct name. This can be a problem with some of the types defined in the Standard Library, where the normal name of the type is actually a typedef for a particular template instantiated with some other type, usually with multiple template parameters. For example, the following will not work to incompletely declare the std::string class:
class std::string;
在Google C++風格指南中,指出盡可能地避免使用前置聲明。而在《Using Incomplete(Forward) Declarations》中,指出能用前置聲明代替#include的時候,應盡量用前置聲明。
以下的內容是摘自:http://stackoverflow.com/questions/553682/when-can-i-use-a-forward-declaration
#ifndef FBC_MESSY_TEST_FORWARD_DECLARATION_HPP_
#define FBC_MESSY_TEST_FORWARD_DECLARATION_HPP_// reference: http://stackoverflow.com/questions/553682/when-can-i-use-a-forward-declaration/*Put yourself in the compiler's position: when you forward declare a type,all the compiler knows is that this type exists; it knows nothing aboutits size, members, or methods. This is why it's called an incomplete type.Therefore, you cannot use the type to declare a member, or a base class,since the compiler would need to know the layout of the type.
*/
// Assuming the following forward declaration.
class X;// Here's what you can and cannot do.// 1. What you can do with an incomplete type:
// 1.1 Declare a member to be a pointer or a reference to the incomplete type:
class Foo_1 {X *pt1;X &pt2;
};// 1.2 Declare functions or methods which accept/return incomplete types:
void f1(X);
X f2();/* 1.3 Define functions or methods which accept/return pointers/references tothe incomplete type (but without using its members): */
void f3(X*, X&) {}
X& f4() { X* x = nullptr; return *x; }
X* f5() { X* x = nullptr; return x; }// 2. What you cannot do with an incomplete type:
// 2.1 Use it as a base class
// class Foo_2 : X {} // compiler error!// 2.2 Use it to declare a member:
/* class Foo_2 {X m; // compiler error!
}; */// 2.3 Define functions or methods using this type
// void f6(X x) {} // compiler error!
// X f7() {} // compiler error!/* 2.4 Use its methods or fields,in fact trying to dereference a variable with incomplete type */
/* class Foo_3 {X *m;void method() {m->someMethod(); // compiler error!int i = m->someField; // compiler error!}
}; *//*When it comes to templates, there is no absolute rule:whether you can use an incomplete type as a template parameter isdependent on the way the type is used in the template.
*//*"In computer programming, a forward declaration is a declaration of an identifier(denoting an entity such as a type, a variable, or a function) for which theprogrammer has not yet given a complete definition."In C++, you should forward declare classes instead of including headers.Don’t use an #include when a forward declaration would suffice.When you include a header file you introduce a dependencythat will cause your code to be recompiled whenever the header file changes.If your header file includes other header files, any change to those files willcause any code that includes your header to be recompiled.Therefore, you should prefer to minimize includes,particularly includes of header files in other header files.You can significantly reduce the number of header filesyou need to include in your own header files by using forward declarations.
*/#endif // FBC_MESSY_TEST_FORWARD_DECLARATION_HPP_
GitHub: https://github.com/fengbingchun/Messy_Test
總結
以上是生活随笔為你收集整理的C++中前置声明介绍的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: Caffe源码中common文件分析
- 下一篇: 开源软件License汇总