2015年8月16日 星期日

物件編譯和前置宣告

參考 http://www.dotblogs.com.tw/v6610688/archive/2013/12/05/how_to_class_include_each_other.aspx

像之前講的,編譯器會將每個.cpp編譯成物件檔.o,最後再用連結器link起來變成exe

那至於怎麼編譯呢,就我理解只要把它想成您編譯的.cpp,裡面有使用到的變數,函式及class,他可以找的到定義,而您的語法又沒問題,就可以編一成一個.o

我這邊舉一連串的例子來讓您理解,舉個例:
a.cpp
void abc()
{
        A b;
}

這個編譯是會出錯的,他會說您沒有定義A,所以您要如何解決咧,就是要在他前面宣告一個實體的structclass,像這樣
class a
{
public:
     a(){};
     ~a(){};
};

void abc()
{
        a b;
}

這樣編譯就會過了


要是您的.cpp上方沒有宣告,其實您可以拿到.h中宣告,並include

a.h
class a
{
public:
     a(){};
    ~a(){};
};

a.cpp
#include “a.h”
void abc()
{
        a b;
}

這樣他就會去include的地方找定義

其實這樣寫法是有問題的,因為通常您程式寫很大時,常常會亂掉,一不小心include太多層,導致同一個.h不小心會include兩次,造成重複定義

所以我們保險起見,有兩種寫法:
1.      舊式
a.h
#ifndef A_H
#define A_H
class a
{
public:
     a(){};
    ~a(){};
};
#endif

a.cpp
#include “a.h”
void abc()
{
        a b;
}

2.      新式

a.h
class a
{
public:
    a(){};
    ~a(){};
};

a.cpp
#pragma once
#include “a.h”
void abc()
{
        a b;
}

當然也可以兩個都加,因為只不過多個一行,不礙事

這樣就不會發生include多次的問題了(我記得之前的文章有講過原因)


在這邊要注意一件事情,當您在程式中宣告的是一個物件(不管在哪,classstruct),他都會去找他的定義(向上面範例一樣),那要是您宣告的是一個物件指標呢,其實用前置宣告就可以解決了,如下:

註:前置宣告就是向下面紅字一樣,告知編譯器,您這個class存在,在其他地方會實體化

1.      在函式內,
Class a;
void abc()
{
        a b;
}

2.      class
Class a;
Class a
{
Public:
       A* b;
}

3.      就任何地方,只要他程式碼往上找找的到就可以(包括寫在標頭檔),像下面這樣也行(還記得之前提的生命週期吧)
Class a
{
Public:
        Class a;
        A* b;
}


這樣就達到基本的寫法,通常我們在class內定義都會定義指標,不會直接宣告物件,因為會發生我參考網頁上面的那種情況,就是兩個class互相include,因為編譯時互相跳來跳去(連結有寫,我就不打了),導致有定義沒找到,

也就是,您只要照我下面寫法,會比較不會遇到一些Bug
1.      就是.h有使用到的物件,請宣告成指標,並在前面加上前置宣告(不直接include標頭檔)
2.      .cpp裡就include您物件定義的標頭檔
3.      .h不是實體化任何東西(函式或是class裡的函式),請都移至.cpp定義

a.h
//前置宣告
class b;
class a
{
public:
    a();
    ~a();
    Void zzz();
    B* a;
};

a.cpp
#pragma once
#include “b.h”
#include “a.h”

A::a()
{}

A::~a()
{}

 

Void a::zzz()
{
        A = new b();
        Delete A;
}

b.h
//前置宣告
class a;
class b
{
public:
    b();
    ~b();
    zzz();
    a* b
};

b.cpp
#pragma once
#include “a.h”
#include “b.h”

b::b()
{}

b::~b()
{}

Void b::zzz()
{
        A = new b();
        Delete A;
}

這樣基本上是我目前寫Code寫得最成功的寫法(目前都這樣寫),真的,不這樣寫Code會卡死,當然還是鼓勵自己試試看錯誤寫法,畢竟您沒看到真的跳出錯誤,您怎麼知道我不是騙您的(),程式設計師一開始就摸不會有問題的東西,是不會成長的(要牢記)


八月份就到這裡了,原本沒空弄得(加班加到吐血,還好之前有多打一點)
Blogger還真的很麻煩,排版很累,基本上就看看就好,上班很累,沒時間做得很完美,
12月份應該會按時間貼文章

沒有留言:

張貼留言