iT邦幫忙

0

物件??類別??

大家好,小弟接觸程式設計也一陣子了,但關於以下的問題真的還是有點難以理解

類別(Class)跟物件(Object)的關係,真的很像"先有雞還是先有蛋"這問題
類別裡面可以有物件?物件裡面可以有類別?實體?靜態?
有沒有誰可以專業的用比喻的方式來形容他們的關係???用設計圖&房子的例子形容總覺得稍稍沒有抓到精隨,希望各位IT界已經是老鳥們一起討論看看~~~~

20點奉上!

過了幾年再回來看看自己問的蠢問題
,真的覺得自己進步好多阿,從一個物件類別搞不清楚的新手,到了現在變成微軟的技術顧問,
中間的努力,但概只有自己能懂

看更多先前的討論...收起先前的討論...
外獅佬 iT邦大師 1 級 ‧ 2015-01-29 16:20:54 檢舉
akitosun提到:
類別裡面可以有物件?物件裡面可以有類別?

有嗎?






最後這個例子
你應該不會忘記了
外獅佬 iT邦大師 1 級 ‧ 2015-01-29 16:24:06 檢舉
灑花灑花
外獅佬 iT邦大師 1 級 ‧ 2015-01-29 16:24:58 檢舉
akitosun提到:
先有雞還是先有蛋

這個基本上早有定論
先有雞,這個雞的祖先稱為『原雞』
一般真正的老鳥是不會去問這種問題的(因為沒什麼營養)
如果樓主真的太閒
可以看保哥的解答
一次滿足你好多願望
外獅佬 iT邦大師 1 級 ‧ 2015-01-29 16:27:06 檢舉
比出奇蛋好用開心
summertw iT邦好手 1 級 ‧ 2015-01-30 08:50:24 檢舉
iT邦幫忙MVPwiselou提到:
『原雞』

重點~~
可以吃嗎??
Akito Sun iT邦新手 5 級 ‧ 2015-01-30 09:44:35 檢舉
其實我就是看了那篇後才會有這篇的疑問"OTZ
Akito Sun iT邦新手 5 級 ‧ 2015-01-30 09:48:27 檢舉
最後一張我笑出來了!!神回覆!!XD噎到
Akito Sun iT邦新手 5 級 ‧ 2015-01-30 09:51:48 檢舉
其實我有特別去查了一下WIKI,真的有這個說法http://zh.wikipedia.org/wiki/%E5%85%88%E6%9C%89%E9%B8%A1%E8%BF%98%E6%98%AF%E5%85%88%E6%9C%89%E8%9B%8B,但這說法扯到了蛋跟雞的"定義",以下轉自WIKI
雞蛋」的概念分析[編輯]
Mitchell Moffit和Gregory Brown認為,先有雞或先有(雞)蛋的問題源自於「雞蛋」概念的歧義:如果「雞蛋」的定義是「孵出雞的蛋」,則演化上應是先由「原型雞」產下第一顆雞蛋,再由第一顆雞蛋孵出第一隻雞,故先有雞蛋。而如果「雞蛋」的定義是「由雞產下的蛋」,則演化上應是先由「原型雞」產下一顆基因變異的「原型雞蛋」,由該「原型雞蛋」孵出第一隻雞,再由第一隻雞產下第一顆雞蛋,故先有雞。[16]
summertw iT邦好手 1 級 ‧ 2015-01-30 13:11:26 檢舉
akitosun提到:
「原型雞」==>「原型雞蛋」==>第一隻雞==>第一顆雞蛋,故先有雞。

重點...
到底這【雞】能不能吃啊...
如果原始人,當時吃了【原型雞】....那麼,現在就沒有所有的【雞】...是吧..
所以,結論,當時原始人,認為【原型雞】不能吃...
Akito Sun iT邦新手 5 級 ‧ 2015-01-30 15:05:24 檢舉
可能他們也知道禽流感吧(?
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中
7
weiclin
iT邦高手 4 級 ‧ 2015-01-31 18:55:36
最佳解答

關於這個齁..我是這樣想啦
類別跟物件並不是先有雞還是先有蛋的問題
而是你要用什麼角度去看待這個世界

如果我們現在要寫個遊戲, 每個角色有三個屬性: str, int, hp
攻擊力計算公式: atk = (str * 2) + int
防禦力計算公式: def = str + (int * 2)
傷害計算公式: dmg = atk - def

那麼如果有 a 與 b 兩個角色互相攻擊對方, 可以這樣寫:

<pre class="c" name="code">
atk_a = str_a * 2 + int_a;
def_a = str_a + int_a * 2;

atk_b = str_b * 2 + int_b;
def_b = str_b + int_b * 2;

hp_a -= atk_b - def_a;
hp_b -= atk_a - def_b;

當然這樣子寫, 如果要動態增加角色就麻煩了, 所以針對動態增加角色做點改進
我們把每一種屬性都用一個陣列來存放: str_array, int_array, hp_array
所以上面的程式可以修改一下, 這樣就算要再冒出個 c 或 d 都不是問題了:

<pre class="c" name="code">
atk_a = str_array[a] * 2 + int_array[a];
def_a = str_array[a] + int_array[a] * 2;

atk_b = str_array[b] * 2 + int_array[b];
def_b = str_array[b] + int_array[b] * 2;

hp_array[a] -= atk_b - def_a;
hp_array[b] -= atk_a - def_b;

這樣的寫法有個缺點, 公式散落在程式裡並且重複出現了, 若是要修改公式就得每個都找出來
為了避免修改公式發生遺漏, 我們將各個公式使用函式來計算:

<pre class="c" name="code">
function calc_atk(str, int) {
    return str * 2 + int;
}

function calc_def(str, int) {
    return str + int * 2;
}

function calc_dmg(str_a, int_a, str_b, int_b) {
    return calc_atk(str_a, str_b) - calc_def(str_b, int_b);
}

hp_array[a] -= calc_dmg(str_array[b], int_array[b], str_array[a], int_array[a]);
hp_array[b] -= calc_dmg(str_array[a], int_array[a], str_array[b], int_array[b]);

改成這樣還是有個明顯的缺點, 如果我們想要增加更多的屬性怎麼辦?
若是公式需要三個屬性, 就得丟六個參數進去 calc_dmg, 這已經是會讓人看了頭暈的數量了
所以我們建立了一個資料結構, 就叫做 character
用 C 語言寫長這樣:

<pre class="c" name="code">
typedef struct character {
    int str;
    int intellect; // int是保留字, 所以改成 intellect
    int hp;
} character;
// 然後在主程式裡就這樣寫:
character a, b;

PHP 或其它語言可以用 array 或 hash:

<pre class="c" name="code">
$a = array(
    "str" => 0,
    "int" => 0,
    "hp" => 0,
);

然後就可以修改我們的 function, 整個程式改成這樣:

<pre class="c" name="code">
function calc_atk(char) {
    return char.str * 2 + char.int;
}

function calc_def(char) {
    return char.int * 2 + char.str;
}

function calc_dmg(attacker, defender) {
    return calc_atk(attacker) - calc_def(defender);
}

a.hp -= calc_dmg(b, a);
b.hp -= calc_dmg(a, b);

到目前為止還沒用到什麼物件與類別, 程式一樣寫得很開心
可是現在寫的這些函式其實專門用來處理角色的資料結構, 而且別的地方又用不到, 看著心煩
那我們有沒有辦法把這些函式黏到那資料結構上面去? 於是類別派上用場了:

<pre class="c" name="code">
class Character {
    str;
    int;
    hp;

    function calc_atk() {
        return str * 2 + int;
    }

    function calc_def() {
        return int * 2 + str;
    }

    function calc_dmg_to(defender) {
        return calc_atk() - defender.calc_def();
    }

    function attack_to(defender) {
        defender.hp -= calc_dmg_to(defender);
    }
}

a.attack_to(b)
b.attack_to(a)

這樣子, 我們的主程式只剩下兩行, 乾淨清爽
可以說類別的概念, 就是把一個資料結構與操作此資料結構的函式給綁定在一起, 是一種分門別類的概念
類別內的資料結構就是一些欄位, 可以填資料進去
而物件的本質呢, 其實就是這些欄位實際填進去的資料了
所以物件與類別是一體兩面, 是一種組織程式的方法
當你決定這個地方要套用物件導向的概念去做的時候, 它們就同時產生了

從這個角度來延伸, 就能夠討論類別與物件裡面到底能放什麼東西
類別既然是一種組織資料與函式的方法, 那我們當然可以在類別內再分成細項
就像將流程切割成幾個子流程, 或增加別的流程那樣
物件代表的是實際上的資料, 那資料內也當然可能再包含其它種類的資料

接著來談談你提到的兩個詞
實體這詞就是物件的意思, 基本上可當成同義字去理解
而靜態呢, 說白了就是一種全域變數或函式, 只是綁定在某個類別裡面
例如我們想要給每個新建立的角色一個編號, 可以這樣做:

<pre class="c" name="code">
char_id = 0;
a = new Character(char_id++);
b = new Character(char_id++);

這樣子 a 與 b 都有一個代表自己的 id
但 char_id 這個全域變數我們只用來給角色做編號, 有沒有辦法把它也黏到 Character 類別裡呢?
靜態欄位就是用來做這事情的:

<pre class="c" name="code">
class Character {
    static _id = 0;
    char_id;
    // 然後在建構式:
    Character() {
        char_id = _id++;
    }
......

// 接著我們就不需要從外部給 id 了:
a = new Character(); // id = 0
b = new Character(); // id = 1

靜態方法呢, 其實也是相同的道理, 它是一個函式, 而且跟一個類別關係密切
例如我們想要知道兩個角色誰比較硬, 可以寫一個函式去處理:

<pre class="c" name="code">
function get_harder(a, b) {
    return a.calc_def() > b.calc_def() ? a : b;
}

可是這函式跟類別關係太密切了, 我又想要把這函式黏到類別上去
而且希望保持不用建立物件就能呼叫, 於是這樣處理:

<pre class="c" name="code">
class Character {
    static function get_harder(char1, char2) {
        return char1.calc_def() > char2.calc_def() ? char1 : char2;
    }
......
// 然後在程式裡這樣使用:
use_char = Character.get_harder(a, b);

整篇下來, 都在把相關的東西圈一圈黏在一起 xD
希望看完不會害你更混亂~驚

pantc328 iT邦高手 1 級 ‧ 2015-02-02 09:20:46 檢舉

weiclin提到:
說白了就是一種全域變數或函式

是沒錯,但
這玩法多了
妳研究DesignPattern 一些 Factory,Singleton 都用到靜態用法

pantc328 iT邦高手 1 級 ‧ 2015-02-02 09:28:01 檢舉

weiclin提到:
實體這詞就是物件的意思, 基本上可當成同義字去理解

萬事皆物件
int,boolean 也是物件,宣告時會自己產生物件在堆疊的位置,參照和預設值
Class 轉物件需要實例化,會在Hash配置一塊記億體空間,然後物件指標指到Hash位置

6
外獅佬
iT邦大師 1 級 ‧ 2015-01-29 16:07:19

類別像是設計圖
物件則是實際的成品

fillano iT邦超人 1 級 ‧ 2015-01-29 16:27:01 檢舉

而且這不是先有雞還是先有蛋的問題,一定先有class。

外獅佬 iT邦大師 1 級 ‧ 2015-01-29 16:28:29 檢舉

所以是...先有class才有雞跟蛋的筆記筆記

兩位大師的對答
讓在下不禁想起
這隻青蛙
讚

5
mis2000lab
iT邦好手 1 級 ‧ 2015-01-29 16:58:00

當一個東西,自己沒有用到、自己沒有感覺的時候
別人講的天花亂墜,還是不懂(無法體會)

很多初學者連基本的程式都還不會寫(不會動),
這時候就去碰OOP,也是霧裡看花

如果您寫好一支程式,然後請「前輩」幫你看看
哪裡能改進?

這時候您就可以發覺:原來如此,可以變成這樣

有段佛經故事:

師父說:你要找一個「能讓你懂」的人

徒弟說:師父,那就是你,不是嗎?

師父說:不對!那個人.....其實是你自己!

OOP,市面上有很多書,很多老師在講(包含學校也上過課)
但聽不懂就是聽不懂,沒有感覺啊!

我建議你,也去找一個「能讓你懂」的人
就像寫作文,你得先寫出來,然後請老師幫你「改」!
用「修改前」「修改後」的比較,讓您懂得:OOP的寫法有哪些好處?不這樣寫有哪些壞處?

我在這邊上課(不是教課喔,我在上這位老師的課)
http://www.allenkuo.com/edm/OOP201404.html

另外,一個ASP.NET MVC的前輩給初學者的建議:
學習MVC以前,先練好OOP
http://www.dotblogs.com.tw/mis2000lab/archive/2014/06/16/mvc_or_web_form_20140616.aspx

0
kentyeh
iT邦新手 5 級 ‧ 2015-01-30 14:03:36

以我們自已為例
人類就是 class(類別)
而你我就是 instance(實體),
你我是屬於人類,但人類並不代表你或是我,
你我終有一天會消失,但只要有人存在,人類就會一直存在。

至於靜態,那是指上帝,
你無法說上帝是class或是instance,
因為以我們的角度那是無法理解的,
在instance的眼中,只知道那原本就是一直存在那裡

0
pantc328
iT邦高手 1 級 ‧ 2015-01-31 13:25:51

public class Car
{
public int speed{};
public float gas{};
}

public void Main(....)
{
Car MyCar=new Car();
Car girlfirendCar=new Car();
}

................
這樣什麼是Class,什麼是 instance??
是先雞,先蛋??

我要發表回答

立即登入回答