C++學習 之 初識頭文件


聲明
            本人自學C++, 沒有計算機基礎,在學習的過程難免會出現理解錯誤,出現風馬牛不相及的現象,甚至有可能會貽笑大方。 如果有幸C++大牛能夠掃到本人的博客,誠心希望大牛能給予批評與指正!不勝感激!
            學習的過程分為初識、入門、進階三個階段。
            因為對C++沒有什么了解,這樣的學習設定可能也有失准確性。望兄弟們多指點。謝謝!



目錄:
科普---- 引用頭文件
1. 引用頭文件的作用
2. 頭文件的結構及作用
3. 常用C++頭文件及描述
4. 編寫頭文件
回顧

科普

  • 頭文件的引用方式

今天我們要開始學習頭文件了。還記得我們第一天學習時寫的“Hello world!” 么?還記得頭文件是怎么被引入的么?就是那個"hello world!"第一行代碼啊!

啥你忘記了 ?回家跪方便面去,不許碎!哈哈,就是#inlude 這一行了。iostream 就是頭文件,#include 是告訴程序,我現在需要引用這個文件的內容。

昨天我也問自己,<> 是干嘛的,現在我可以告訴自己,一個大於號一個小於號,兩個符號標明了符號間的內容代表的是C++標准頭文件。啥?你問我難道還有不標准的么?我X,你太聰明了,你就是天才啊。日后必成大器啊。

還有另外一種標識為頭文件的符號是: “”, 對的,就是雙引號。但是這種引用頭文件的方式,並不能說不標准 ,那兩人者的區別在哪里呢?一會兒我們會說到。

也就是說引用頭文件有兩種寫法:

#include 

#include "iostream"


那這兩種寫法有什么區別呢?區別可大了!

前者告訴程序,你要C++安裝路徑中庫頭文件默認存儲路徑下去找頭文件,比如 我環境里就是/usr/inlude/C++/4.8 這個路徑里查找。而后者,則告訴程序去源代碼的相對路徑去找。 ,你可別問我啥叫相對路徑啊~不理你,你逗我玩兒。

我們一起來了解頭文件吧。

 

1. 引用頭文件的作用

   在了解頭文件前,我們先了解下調用頭文件有什么作用吧。

   為了了解調用頭文件的作用,先來看下istream 頭文件的內容,為啥不直接看iostream呢?為啥啊~這怎么說呢,你難住我了。。。因為iostream只不過是把istream和ostream封裝了下,這么說可以么?其實不完全正確的。大牛們勿噴,我覺得在初學C++的時候,這樣理解是最容易理解的。

   關於iostream標准庫介紹比較詳細的可以看http://www.cppblog.com/yuqilin1228/archive/2010/03/26/110620.html

   我還沒有能力理解那么深入。。嘿嘿,慢慢來。

   但是這不影響所了解引用頭文件的作用:調用了頭文件,就等於賦予了調用某些函數的權限。不好理解么?那這樣吧,你把頭文件想象成一個廚櫃,里面有各種廚具。一個廚師學徒就是我們的源代碼,大廚就是編譯器。這時 廚師學徒(源代碼)想要學炒菜(編譯源代碼),去找大廚指點(找G++編譯器),大廚跟他說,第一步,你看到那個?櫃(調用了頭文件)沒?學徒說看到了,大廚說你去那個廚櫃里拿廚具(給了學徒使用廚櫃里廚具的權限)。

   我個去,我要把自己繞暈了。。。。。你明白沒?當然G++編譯源代碼的過程可能跟我描述的過程不一樣啊,這里的主要的目的也不是為了說明編譯過程,而是想說明調用頭文件的作用。

   那么引用頭文件作用也就是
   1. 指導編譯器查尋頭文件的路徑  
   2. 給源代碼使用庫文件內容的權限
   

2. 頭文件的結構及作用


   我們知道調用頭文件,便有了使用頭文件中的函數的權限。那么頭文件本身是用來干嘛的呢?通過查看頭文件的內容,我們會發現頭文件本身只進行聲明或者定義函數、類結構、數據接口等。
   那我們先來看看頭文件吧。
   
   想要查看頭文件,我們首先應該知道C++的頭文件存儲在哪里吧?嘿嘿,你不知道了吧?來來來,見證神奇的時刻到了:C++的標准頭文件一般情況下存放在/usr/include/c++/$releaseOfC++
   比如我現在剛開始學C++,相對於我這個時代來說已經是穩定版里最高版本了,是4.8的,那我可以到/usr/include/c++/4.8 這個路徑下去查看C++的標准頭文件。
   
   這里為了節省篇副,我選了一個比較小的頭文件:typeinfo

    // RTTI support for -*- C++ -*-
    // Copyright (C) 1994-2013 Free Software Foundation, Inc.
    //
    // This file is part of GCC.
    //
    // GCC is free software; you can redistribute it and/or modify
    // it under the terms of the GNU General Public License as published by
    // the Free Software Foundation; either version 3, or (at your option)
    // any later version.
    //
    // GCC is distributed in the hope that it will be useful,
    // but WITHOUT ANY WARRANTY; without even the implied warranty of
    // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
    // GNU General Public License for more details.
    //
    // Under Section 7 of GPL version 3, you are granted additional
    // permissions described in the GCC Runtime Library Exception, version
    // 3.1, as published by the Free Software Foundation.

    // You should have received a copy of the GNU General Public License and
    // a copy of the GCC Runtime Library Exception along with this program;
    // see the files COPYING3 and COPYING.RUNTIME respectively. If not, see
    // <http://www.gnu.org/licenses/>.

    /** @file typeinfo
     * This is a Standard C++ Library header.
     */

    #ifndef _TYPEINFO
    #define _TYPEINFO

    #pragma GCC system_header

    #include <exception>
    #if __cplusplus >= 201103L
    #include <bits/hash_bytes.h>
    #endif

    #pragma GCC visibility push(default)

    extern \"C++\" {

    namespace __cxxabiv1
    {
      class __class_type_info;
    } // namespace __cxxabiv1

    // Determine whether typeinfo names for the same type are merged (in which
    // case comparison can just compare pointers) or not (in which case strings
    // must be compared), and whether comparison is to be implemented inline or
    // not. We used to do inline pointer comparison by default if weak symbols
    // are available, but even with weak symbols sometimes names are not merged
    // when objects are loaded with RTLD_LOCAL, so now we always use strcmp by
    // default. For ABI compatibility, we do the strcmp inline if weak symbols
    // are available, and out-of-line if not. Out-of-line pointer comparison
    // is used where the object files are to be portable to multiple systems,
    // some of which may not be able to use pointer comparison, but the
    // particular system for which libstdc++ is being built can use pointer
    // comparison; in particular for most ARM EABI systems, where the ABI
    // specifies out-of-line comparison. The compiler\'s target configuration
    // can override the defaults by defining __GXX_TYPEINFO_EQUALITY_INLINE to
    // 1 or 0 to indicate whether or not comparison is inline, and
    // __GXX_MERGED_TYPEINFO_NAMES to 1 or 0 to indicate whether or not pointer
    // comparison can be used.

    #ifndef __GXX_MERGED_TYPEINFO_NAMES //預處理塊
    // By default, typeinfo names are not merged.
    #define __GXX_MERGED_TYPEINFO_NAMES 0
    #endif

    // By default follow the old inline rules to avoid ABI changes.
    #ifndef __GXX_TYPEINFO_EQUALITY_INLINE
      #if !__GXX_WEAK__
        #define __GXX_TYPEINFO_EQUALITY_INLINE 0
      #else
        #define __GXX_TYPEINFO_EQUALITY_INLINE 1
      #endif
    #endif //預處理結束

    namespace std // 聲明了命名空間STD
    {
      /**
       * @brief Part of RTTI.
       *
       * The @c type_info class describes type information generated by
       * an implementation.
      */
      class type_info
      {
      public:
        /** Destructor first. Being the first non-inline virtual function, this
         * controls in which translation unit the vtable is emitted. The
         * compiler makes use of that information to know where to emit
         * the runtime-mandated type_info structures in the new-abi. */
        virtual ~type_info();

        /** Returns an @e implementation-defined byte string; this is not
         * portable between */
        const char* name() const _GLIBCXX_NOEXCEPT
        { return __name[0] == \'*\' ? __name + 1 : __name; }

    #if !__GXX_TYPEINFO_EQUALITY_INLINE
        // In old abi, or when weak symbols are not supported, there can
        // be multiple instances of a type_info object for one
        // type. Uniqueness must use the _name value, not object address.
        bool before(const type_info& __arg) const _GLIBCXX_NOEXCEPT;
        bool operator==(const type_info& __arg) const _GLIBCXX_NOEXCEPT;
    #else
      #if !__GXX_MERGED_TYPEINFO_NAMES
        /** Returns true if @c *this precedes @c __arg in the implementation\'s
         * collation order. */
        // Even with the new abi, on systems that support dlopen
        // we can run into cases where type_info names aren\'t merged,
        // so we still need to do string comparison.
        bool before(const type_info& __arg) const _GLIBCXX_NOEXCEPT
        { return (__name[0] == \'*\' && __arg.__name[0] == \'*\')
            ? __name < __arg.__name
            : __builtin_strcmp (__name, __arg.__name) < 0; }

        bool operator==(const type_info& __arg) const _GLIBCXX_NOEXCEPT
        {
          return ((__name == __arg.__name)
                  || (__name[0] != \'*\' &&
                      __builtin_strcmp (__name, __arg.__name) == 0));
        }
      #else
        // On some targets we can rely on type_info\'s NTBS being unique,
        // and therefore address comparisons are sufficient.
        bool before(const type_info& __arg) const _GLIBCXX_NOEXCEPT
        { return __name < __arg.__name; }

        bool operator==(const type_info& __arg) const _GLIBCXX_NOEXCEPT
        { return __name == __arg.__name; }
      #endif
    #endif
        bool operator!=(const type_info& __arg) const _GLIBCXX_NOEXCEPT
        { return !operator==(__arg); }

    #if __cplusplus >= 201103L
        size_t hash_code() const noexcept
        {
    # if !__GXX_MERGED_TYPEINFO_NAMES
          return _Hash_bytes(name(), __builtin_strlen(name()),
                             static_cast<size_t>(0xc70f6907UL));
    # else
          return reinterpret_cast<size_t>(__name);
    # endif
        }
    #endif // C++11

        // Return true if this is a pointer type of some kind
        virtual bool __is_pointer_p() const;

        // Return true if this is a function type
        virtual bool __is_function_p() const;

        // Try and catch a thrown type. Store an adjusted pointer to the
        // caught type in THR_OBJ. If THR_TYPE is not a pointer type, then
        // THR_OBJ points to the thrown object. If THR_TYPE is a pointer
        // type, then THR_OBJ is the pointer itself. OUTER indicates the
        // number of outer pointers, and whether they were const
        // qualified.
        virtual bool __do_catch(const type_info *__thr_type, void **__thr_obj,
                                unsigned __outer) const;

        // Internally used during catch matching
        virtual bool __do_upcast(const __cxxabiv1::__class_type_info *__target,
                                 void **__obj_ptr) const;

      protected:
        const char *__name;

        explicit type_info(const char *__n): __name(__n) { }

      private:
        /// Assigning type_info is not supported.
        type_info& operator=(const type_info&);
        type_info(const type_info&);
      };

      /**
       * @brief Thrown during incorrect typecasting.
       * @ingroup exceptions
       *
       * If you attempt an invalid @c dynamic_cast expression, an instance of
       * this class (or something derived from this class) is thrown. */
      class bad_cast : public exception
      {
      public:
        bad_cast() _GLIBCXX_USE_NOEXCEPT { }

        // This declaration is not useless:
        // http://gcc.gnu.org/onlinedocs/gcc-3.0.2/gcc_6.html#SEC118
        virtual ~bad_cast() _GLIBCXX_USE_NOEXCEPT;

        // See comment in eh_exception.cc.
        virtual const char* what() const _GLIBCXX_USE_NOEXCEPT;
      };

      /**
       * @brief Thrown when a NULL pointer in a @c typeid expression is used.
       * @ingroup exceptions
       */
      class bad_typeid : public exception
      {
      public:
        bad_typeid () _GLIBCXX_USE_NOEXCEPT { }

        // This declaration is not useless:
        // http://gcc.gnu.org/onlinedocs/gcc-3.0.2/gcc_6.html#SEC118
        virtual ~bad_typeid() _GLIBCXX_USE_NOEXCEPT;

        // See comment in eh_exception.cc.
        virtual const char* what() const _GLIBCXX_USE_NOEXCEPT;
      };
    } // namespace std

    } // extern \"C++\"

    #pragma GCC visibility pop

    #endif

通過這個文件,我們發現,C++的標准頭文件,主要包含三個部分:
     1、頭文件開始處的版權和版本聲明
     2、預處理塊
     3、函數和類結構聲明部分等。

啥你問我,我是怎么知道有函數和類結構的?

這個么。。。嘿嘿,俺還學過shell的。對比下就猜到了。

函數的結構一般是這樣的:

function_name()

{
………………
}

至於類嘛 ?class 英文翻譯過來不就是類么?嘿嘿

你現在看這個頭文件會不會跟我一樣一頭露水呢?我就納悶了,這都啥東西啊?class是啥東西啊?namespace 又是啥東東啊?const 這又是個啥東西啊?

以前很多次,我在學東西的時候,一遇到這種情況,我就會想,XX,好難啊,這都什么東西啊,怎么一開始就讓我看這么復雜、晦澀難懂的東西呢。。什么邏輯嘛!

如果你是跟我一樣的,不要急,我們這里,只是想來說明頭文件包含了哪些東西,弄清楚頭文件本身是干嘛的,這就足夠了,至於要看懂頭文件的內容,我們后面一起學習,相信不久看懂它,還不如探囊取物一般?嘿嘿

都知道了頭文件的組成了,還不知道頭文件的作用么?就是聲明函數和類結構啊~

現在,我們知道了頭文件的作用(聲明函數、類結構等),調用頭文件的作用(使我們擁有直接調用頭文件中的函數、類的權限)。眼珠子一轉,我瞬間明白了,發明頭文件的人,真的是熊才大略啊。

居然能想到這么牛的方式來簡化我們的工作。為啥這么說呢?你想啊,函數、類結構等在頭文件中聲明過了,我們在編寫源文件過程中,當需要使用某個函數時,如果已經在頭文件中聲明過,那我們直接調用就可以了啊,不用重新編寫了呢!這不就簡化了我們的工作么!

頭文件的最大貢獻,作為初學者看來,就是實現了代碼的重用(在同一個源文件中可以多次使用)和共用(在不同源文件甚至不同工程中都可以共用同一個頭文件)。

3. C++ 常用頭文件及描述

C++都有哪些常用的頭文件呢?每個頭文件的具體作用又是什么呢?

參見:標准C++常用頭文件及描述

4. 編寫頭文件

   555555……  現在怎么可能實現呢?
   通過第二步的分析我們知道頭文件的主體部分包含兩層內容,一層是引用另外一些頭文件,這個沒問題啊,不就是#inlude <頭文件>么,但是另一部分是聲明函數、類結構等信息啊。。。
   別灰心,別喪氣,等我們學習了函數、類以后,再寫頭文件還不手到摛來?嗯嗯,就是這樣,必須的,要循序漸進!
  等學會編寫頭文件了,再把連接搞過來,嗯,就這么定了!

回顧:

通過這一節的學習,我們學習了哪些東西呢?來復習一下:
1. 如何調用頭文件
2. 調用頭文件的作用是什么
3. 頭文件本身的作用是什么
4. 使用頭文件的好處是什么
5. 頭文件的組成結構是怎樣的
6. 關於編寫頭文件。。。。這個還沒學會,放后面再說吧。嘿嘿


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM