(原創) 何時該使用object? 何時該使用reference? 何時該使用pointer? (C/C++)

對於原來會C#、Java,轉而用C++時,總會對C++同時有object、reference、pointer三種機制感到困擾,因為在C#、Java只有object,一切都很單純,但在C++卻很複雜。

在C#如以下的程式

1Foo foo1;
2Foo foo2 = new Foo();


foo1僅宣告了一個物件,但卻尚未建立。
foo2才是宣告了一個物件,且建立了foo2物件。

在C++卻必須這樣寫

1Foo *foo1; // C# : Foo foo1;
2Foo foo2;  // C# : Foo foo2 = new Foo();
3Foo *foo3 = &Foo();    // object on stack
4Foo *foo4 = new Foo(); // object on heap


foo1為指向Foo型別object的pointer,但此時僅有pointer還沒有object,所以等同C#的Foo foo1。

foo2真的是一個object了,相當於C#的Foo foo2 = new Foo();

foo3是一個pointer指向Foo object,此時是一個建立在stack的object,不需手動delete刪除。

foo4是一個pointer指向Foo object,此時是一個建立在heap的object,需手動用delete刪除。

foo1若要繼續指定值

foo1 = &Foo();



foo1 = new Foo();


皆可

總而言之,若要建立在stack上的object,且要直接用該object,直接Foo foo2即可,若想先宣告一個object variable,等日後看情形使用,則要用pointer的Foo *foo1或Foo *foo3 = &Foo();這種方式。

若要建立在heap上的object,則一律使用pointer的Foo *foo4 = new Foo();這種方式。

那何時要建立在stack?何時要建立在heap呢?

若object屬於local object,其scope僅在function裡,此時應建立在stack。

若object屬於static object,在離開function後,希望該object仍存在,此時應建立在heap,該object會一直等到手動下delete時,才會消失。

這是C++和C#語法很大的差異之處!!我ㄧ開始也很不習慣。

若以sematics(語意)而言,C#和C++何者語意較適當?

回想我們在使用基本型別時,如

int i;


此時i這個int object已經建立了,所以C++才模仿基本型別建立的方式使用

Foo foo;


符合Bjarne Stroustrup所謂『建立一個和基本型別一樣好用的class』想法,所以語法和基本型別一樣。

C#的想法則是,將型別分成value type和reference type,int屬於value type,固用int i語法,而object屬於reference type,一律使用new語法且建立在heap,因為有GC,所以沒有delete問題。

理解後,兩者都有他的道理!!

何時會用reference呢?

將object傳到function裡,且希望使用polymorphism時,會使用reference,當然此時用pointer亦可,不過習慣上大都使用reference,但不可用object,這樣會造成object slicing,就沒有polymorphism了。

/* 
(C) OOMusou 2006 
http://oomusou.cnblogs.com

Filename    :Polymorphism.cpp
Compiler    : Visual C++ 8.0 / ISO C++
Description : Demo how to use Object Decomposition and Polymorphism.
Release     : 01/12/2007 1.0
*/

#include 
<iostream>
#include 
<vector>
#include 
<string>

using namespace std;

class Student {
protected:
  
// constructor of abstract base class, since student
  
// can't be initiated, constructor just can be called
  
// by constructor of derived class, so put it in protected
  
// level.
  Student(const char* _name) : name(string(_name)) {}

public:
  
string getName() const return this->name; }
  
// pure virtual fuction
  virtual string job() const = NULL;

private:
  
string name;
}
;

// public inheritance
class Bachelor : public Student {
public:
  
// call constructor of abc myself.
  Bachelor(const char* name) : Student(name) {};

public:
  
string job() const return "study"; };
}
;

class Master : public Student {
public:
  Master(
const char* name) : Student(name) {};

public:
  
string job() const return "study, research"; };
}
;

// new class for further 
/*
class Doctor : public Student {
public:
  Doctor(const char* name) : Student(name) {};

public:
  string job() const { return "study, research, teach"; };
};
*/


class Lab {
public:
  
// pass reference of student 
  void add(Student&);
  
void listAllJob() const;

private:
  
// put pointer of student in member vector, can't 
  
// put reference in vector.
  vector<Student *> member;
}
;

void Lab::add(Student& student) {
  
// _student is reference of student object
  
// &_student is pointer of _student reference
  this->member.push_back(&student);
}


void Lab::listAllJob() const {
  
// POWER of Polymorphism !!
  
// (*iter) automatically refer to derived object, 
  
// this is called "dynamic binding".
  
// if you add new object in the future, you don't
  
// need to maintain this code.
  for(vector<Student *>::const_iterator iter = this->member.begin(); iter != this->member.end(); ++iter) {
    cout 
<< (*iter)->getName() << "'s job:" << (*iter)->job() << endl;
  }

}


int main() {
  Bachelor John(
"John");
  Master   Mary(
"Mary");
  
// Doctor   Jack("Jack");

  Lab CSLab;
  CSLab.add(John);
  CSLab.add(Mary);
  
// CSLab.add(Jack);

  CSLab.listAllJob();
}


執行結果

John's job:study
Mary's job:study
, research


73行

void Lab::add(Student& student) {


將物件傳入function,為了要達成polymorphism,所以用了reference。

何時該使用pointer呢?

將object塞進container且要達成polymorphism時,只能使用pointer!!因為object進入container需copy的動作,但reference不支援copy動作,所以不能使用reference,當然也不能使用object,因為會造成object slicing,如此就沒polymorphism了,70行

vector<Student *> member;


就是個例子,vector只能放Student *才能達到polymorphism。

Conclusion
我很早就想寫這一篇了,因為對於我這個C#轉C++的人來說,已經被reference,pointer搞的暈頭轉向,希望藉由這篇經驗的總結,能讓各位在C++的學習上少走些冤枉路。

See Also
(原創) 如何使用pointer和reference達成Polymorphism? (初級) (C++) (OO C++)

posted on 2007-04-01 21:12  真 OO无双  阅读(3636)  评论(1编辑  收藏  举报

导航