(原創) 何時該使用object? 何時該使用reference? 何時該使用pointer? (C/C++)
對於原來會C#、Java,轉而用C++時,總會對C++同時有object、reference、pointer三種機制感到困擾,因為在C#、Java只有object,一切都很單純,但在C++卻很複雜。
在C#如以下的程式
2Foo foo2 = new Foo();
foo1僅宣告了一個物件,但卻尚未建立。
foo2才是宣告了一個物件,且建立了foo2物件。
在C++卻必須這樣寫
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若要繼續指定值
或
皆可
總而言之,若要建立在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++何者語意較適當?
回想我們在使用基本型別時,如
此時i這個int object已經建立了,所以C++才模仿基本型別建立的方式使用
符合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();
}
執行結果
Mary's job:study, research
73行
將物件傳入function,為了要達成polymorphism,所以用了reference。
何時該使用pointer呢?
將object塞進container且要達成polymorphism時,只能使用pointer!!因為object進入container需copy的動作,但reference不支援copy動作,所以不能使用reference,當然也不能使用object,因為會造成object slicing,如此就沒polymorphism了,70行
就是個例子,vector只能放Student *才能達到polymorphism。
Conclusion
我很早就想寫這一篇了,因為對於我這個C#轉C++的人來說,已經被reference,pointer搞的暈頭轉向,希望藉由這篇經驗的總結,能讓各位在C++的學習上少走些冤枉路。
See Also
(原創) 如何使用pointer和reference達成Polymorphism? (初級) (C++) (OO C++)