C++中前置声明介绍
前置聲明是指對(duì)類、函數(shù)、模板或者結(jié)構(gòu)體進(jìn)行聲明,僅僅是聲明,不包含相關(guān)具體的定義。在很多場(chǎng)合我們可以用前置聲明來(lái)代替#include語(yǔ)句。
類的前置聲明只是告訴編譯器這是一個(gè)類型,但無(wú)法告知類型的大小,成員等具體內(nèi)容。在未提供完整的類之前,不能定義該類的對(duì)象,也不能在內(nèi)聯(lián)成員函數(shù)中使用該類的對(duì)象。而頭文件則一一告之。
如:class Screen;
前置聲明,也稱前向聲明(forward declaration)。在聲明之后,定義之前,類Screen是個(gè)不完整類型(incomplete type),即已知Screen是一個(gè)類型,但是不知道包含哪些成員。
不完全類型只能以有限方式使用。不能定義該類型的對(duì)象。不完全類型只能用于定義指向該類型的指針及引用,或者用于聲明(而不是定義)使用該類型作為形參類型或返回類型的函數(shù)。
可以通過前置聲明配合指針或引用類型聲明來(lái)減少編譯依賴。
???????? Never #include a header when a forward declaration will suffice.
???????? 前置聲明的作用:
(1)、可以減少編譯依賴、減少編譯時(shí)間(如果頭文件被修改,會(huì)導(dǎo)致多次重新編譯);
(2)、可以隱藏細(xì)節(jié);
(3)、可以減少類大小(前置聲明會(huì)告訴這個(gè)類的存在,而不用提供類定義的所有細(xì)節(jié));
(4)、減少include,防止類間相互引用形成依賴,造成編譯不通過.
以下是在Google C++風(fēng)格指南中對(duì)前置聲明的介紹:
盡可能地避免使用前置聲明。使用#include 包含需要的頭文件即可。
所謂前置聲明(forward declaration)是類、函數(shù)和模板的純粹聲明,沒伴隨著其定義.
優(yōu)點(diǎn):
(1)、前置聲明能夠節(jié)省編譯時(shí)間,多余的 #include 會(huì)迫使編譯器展開更多的文件,處理更多的輸入。
(2)、前置聲明能夠節(jié)省不必要的重新編譯的時(shí)間。 #include 使代碼因?yàn)轭^文件中無(wú)關(guān)的改動(dòng)而被重新編譯多次。
缺點(diǎn):
(1)、前置聲明隱藏了依賴關(guān)系,頭文件改動(dòng)時(shí),用戶的代碼會(huì)跳過必要的重新編譯過程。
(2)、前置聲明可能會(huì)被庫(kù)的后續(xù)更改所破壞。前置聲明函數(shù)或模板有時(shí)會(huì)妨礙頭文件開發(fā)者變動(dòng)其 API.例如擴(kuò)大形參類型,加個(gè)自帶默認(rèn)參數(shù)的模板形參等等。
(3)、前置聲明來(lái)自命名空間std:: 的 symbol 時(shí),其行為未定義。
(4)、很難判斷什么時(shí)候該用前置聲明,什么時(shí)候該用 #include 。極端情況下,用前置聲明代替 includes 甚至都會(huì)暗暗地改變代碼的含義.
結(jié)論:
(1)、盡量避免前置聲明那些定義在其他項(xiàng)目中的實(shí)體.
(2)、函數(shù):總是使用#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++風(fēng)格指南中,指出盡可能地避免使用前置聲明。而在《Using Incomplete(Forward) Declarations》中,指出能用前置聲明代替#include的時(shí)候,應(yīng)盡量用前置聲明。
以下的內(nèi)容是摘自: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
總結(jié)
以上是生活随笔為你收集整理的C++中前置声明介绍的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: Caffe源码中common文件分析
- 下一篇: 开源软件License汇总