C++ 類對象和 指針的區別
轉自:http://blog.csdn.net/ym19860303/article/details/8557746
指針的情況

class Test{ public: int a; Test(){ a = 1; } }; int main() { Test* t1 = new Test(); t1->a = 10; Test* t2 = new Test(); t2->a = 5; cout << "&t1:" << t1 << " a = " << t1->a << endl; cout << "&t2:" << t2 << " a = " << t2->a <<endl; cout << "------------------------------" << endl; t2 = t1; cout << "&t1:" << t1 << " a = " << t1->a << endl; cout << "&t2:" << t2 << " a = " << t2->a <<endl; cout << "------------------------------" << endl; t1->a = 111; t2->a = 222; cout << "&t1:" << t1 << " a = " << t1->a << endl; cout << "&t2:" << t2 << " a = " << t2->a <<endl; return 0; }
對象的情況:

class Test{ public: int a; Test(){ a = 1; } }; int main() { Test t1; t1.a = 10; Test t2; t2.a = 5; cout << "&t1:" << &t1 << " a = " << t1.a << endl; cout << "&t2:" << &t2 << " a = " << t2.a <<endl; cout << "------------------------------" << endl; t2 = t1; cout << "&t1:" << &t1 << " a = " << t1.a << endl; cout << "&t2:" << &t2 << " a = " << t2.a <<endl; cout << "------------------------------" << endl; t1.a = 111; t2.a = 222; cout << "&t1:" << &t1 << " a = " << t1.a << endl; cout << "&t2:" << &t2 << " a = " << t2.a <<endl; return 0; }
轉自:http://blog.csdn.net/neuqbingoye/article/details/7184090

class Student { public: static int number; string name; public: Student() { } void print() // 態成員函數 print() { std::cout < < name < <" : The number of the students is " < < number < < " numbers." < < std::endl; // 調用靜態數據成員 } };
類對象:Student s1 類指針:Student *s2
很關鍵的一點:定義對象實例時,分配了內存,指針變量則未分配類對象所需內存。
類的指針:他是一個內存地址值,他指向內存中存放的類對象(包括一些成員變量所賦的值).
對象,他是利用類的構造函數在內存中分配一塊內存(包括一些成員變量所賦的值).
指針變量是間接訪問,但可實現多態(通過父類指針可調用子類對象),並且沒有調用構造函數。
直接聲明可直接訪問,但不能實現多態,聲明即調用了構造函數(已分配了內存)。
類的對象:用的是內存棧,是個局部的臨時變量.
類的指針:用的是內存堆,是個永久變量,除非你釋放它.
1.在類的聲明尚未完成的情況下,可以聲明指向該類的指針,但是不可聲明該類的對象... 例如:含有純虛成員函數的抽象類。
2.父類的指針可以指向子類的對象..
在應用時:
1.引用成員: 對象用" . "操作符; 指針用" -> "操作符.
2.生命期: 若是成員變量,則是類的析構函數來釋放空間;若是函數中的臨時變量,則作用域是該函數體內.而指針,則需利用delete 在相應的地方釋放分配的內存塊.
注意:用new ,一定要delete..
C++的精髓之一就是多態性,只有指針或者引用可以達到多態。對象不行
類指針的優點:
第一實現多態。
第二,在函數調用,傳指針參數。不管你的對象或結構參數多么龐大,你用指針,傳過去的就是4個字節。如果用對象,參數傳遞占用的資源就太大了
類對象和類指針的區別
轉自:http://blog.sina.com.cn/s/blog_73e0563201017c8u.html
此文章比較全面的總結了類對象和類指針使用的不同

#include <iostream> #include <string> using namespace std; class Student { public: static int number; string name; public: Student() { } void set(string str) { name = str; number++; // 調用靜態數據成員 } void print() // 態成員函數 print() { std::cout < < name < <" : The number of the students is " < < number < < " numbers." < < std::endl; // 調用靜態數據成員 } }; int Student::number = 0; // 靜態數據成員初始化 int main(int argc, char** argv) { Student* s1; s1 = new Student(); s1->set("111"); Student s2; s2.set("222"); s1->print(); s2.print(); return 0; }
對於類student ,定義了一個對象 和一個指針。
類的指針:他是一個內存地址值,他指向內存中存放的類對象(包括一些成員變量所賦的值).
對象,他是利用類的構造函數在內存中分配一塊內存(包括一些成員變量所賦的值).
在應用時:
1.引用成員: 對象用" . "操作符; 指針用" -> "操作符.
2.生命期: 若是成員變量,則是類的析構函數來釋放空間;若是函數中的臨時變量,則作用域是該函數體內.而指針,則需利用delete 在相應的地方釋放分配的內存塊.
注意:用new ,一定要delete..
類的對象:用的是內存棧,是個局部的臨時變量.
類的指針:用的是內存堆,是個永久變量,除非你釋放它.
當類是有虛函數的基類,Func是它的一個虛函數,則調用Func時:
類的對象:調用的是它自己的Func;
類的指針:調用的是分配給它空間時那種類的Func;
對於一個類的對象和這個類的指針(用new運算符分配內存)在應用時有何區別
1.類和對象是兩回事,對象是類的實例;
2.對象是在棧中分配的,使用new生成的對象是在堆中分配的;
3.要發揮虛函數的強大作用,必須使用指針來訪問對象.
指針可以實現多態,直接用對象不行
執行定義對象,在棧空間
new的在堆
類型決定了你能做什么.
其實作用基本一樣 都是為了調用類的成員變量 和成員函數用的
當你希望明確使用這個類的時候,最好使用對象,如果你希望使用C++中的動態綁定,則最好使用指針或者引用
指針和引用用起來更靈活,容易實現多態等
1.在類的聲明尚未完成的情況下,可以聲明指向該類的指針,但是不可聲明該類的對象...
2.父類的指針可以指向子類的對象..
定義對象實例時,分配了內存。指針變量則未分配類對象所需內存,除非new了
指針變量是間接訪問,但可實現多態(通過父類指針可調用子類對象),並且沒有調用構造函數。
直接聲明可直接訪問,但不能實現多態,聲明即調用了構造函數(已分配了內存)。
至於那個效率高要看程序調用過程而定。
C++的精髓之一就是多態性,只有指針或者引用可以達到多態。對象不行
用指針:
第一實現多態。
第二,在函數調用,傳指針參數。不管你的對象或結構參數多么龐大,你用指針,傳過去的就是4個字節。如果用對象,參數傳遞占用的資源就太大了
轉自:http://www.cnblogs.com/ggjucheng/archive/2011/12/14/2287381.html
C++類就是為程序員提供一種建立一個新類型的工具,使這些新類型的使用能夠像內部類型一樣方便。
一個類就是一個用戶定義的類型,如何聲明一個類,形式如下:

class class_name { access_specifier_1: member1; access_specifier_2: member2; ... } object_names;
示例如下:

class Object { public: Object(); ~Object(); //must be public Object(int num); int getNumber(); void setNumber(int num); private: int m_num; };
如何定義一個已聲明的類:

Object::Object() { m_num = 0; } Object::~Object() { } Object::Object(int num) { m_num = num; } int Object::getNumber() { return m_num; } void Object::setNumber(int num) { m_num = num; }
如何實例化和使用一個類:

int main () { Object obj1; Object obj2(110); Object obj3 = Object(119); Object *pObj4 = new Object(); Object *pObj5 = new Object(119); Object objs[10]; printf("obj1.getNumber() = %d\n", obj1.getNumber()); printf("obj2.getNumber() = %d\n", obj2.getNumber()); printf("obj3.getNumber() = %d\n", obj3.getNumber()); printf("pObj4->getNumber() = %d\n", pObj4->getNumber()); printf("pObj5->getNumber() = %d\n", pObj5->getNumber()); for (int i = 0; i < 10; i++) { printf("objs[%d].getNumber() = %d\n",i, objs[i].getNumber()); } delete pObj4; delete pObj5; return 0; }
struct 和union的類聲明
類可以定義不僅可以用關鍵字class,也可以用關鍵字struct和union。
class和struct的概念是相似的,可用struct和class聲明C++的類(即struct可以有數據成員和函數成員)。兩者之間唯一的區別是使用關鍵字struct聲明的類成員默認情況下,是public訪問權限,而使用關鍵字class聲明的類成員默認是private訪問權限。對於所有其他的目的,這兩個關鍵字是等價的。
union的概念是與struct和class聲明類不同的,因為union一次只能存儲一個數據成員,但union也可能擁有函數成員,union類的默認訪問權限是public。
轉自:http://blog.csdn.net/pearl333/article/details/8027358
對象與函數的關系(知道如何把對象指針和引用作為函數參數)
將對象指針作為函數的參數,傳遞給函數處理有兩個好處
1、減少數據分配的時間和空間,提高了程序運行的效率;
2、在被調函數中,可以直接改變實參對象的值,實現函數之間的信息交換。
通過一個例子感受 對象指針作為函數的參數

#include <iostream> using namespace std; class CPoint{ public : CPoint(int x,int y); void copy(CPoint *point); //在成員函數中,參數是對象指針 void setXY(int x,int y); void disp(); private: int m_x; //數據成員 int m_y; }; CPoint::CPoint(int x,int y) //帶參數的構造函數 { m_x=x; m_y=y; } void CPoint::copy(CPoint *point) { m_x=point->m_x; //通過對象指針訪問該對象的數據成員,賦值 m_y=point->m_y; //給調用成員函數的對象的數據成員 } void CPoint::disp(){ cout<<"x="<<m_x<<";y="<<m_y<<endl; } void CPoint::setXY(int x,int y){ m_x=x; m_y=y; } void func(CPoint *p){ //函數的參數是對象指針,通過指針調用對象的成員函數 p->setXY(55,33); } int main() { CPoint p1(5,5),p2(25,25); p1.copy(&p2); //把對象p2的地址賦值給對象指針 p1.disp(); func(&p2); //把對象p2的地址賦值給對象指針 p2.disp(); return 0; }
對象引用作為函數參數:比把對象指針作為函數參數更為普遍,因為使用對象引用作為函數參數不僅具有對象指針的優點,而且使用對象引用更為直觀和簡單。所以在C++中普遍采用對象引用作為函數參數,看例子,注意對比上面的程序:

#include <iostream> using namespace std; class CPoint{ public : CPoint(int x,int y); void copy(CPoint &point); //在成員函數中,參數是對象指針 void setXY(int x,int y); void disp(); private: int m_x; //數據成員 int m_y; }; CPoint::CPoint(int x,int y) //帶參數的構造函數 { m_x=x; m_y=y; } void CPoint::copy(CPoint &point) //函數的參數是對象引用 { m_x=point.m_x; //通過對象引用訪問該對象數據成員,賦值給調用成員函數的對象的數據成員 m_y=point.m_y; } void CPoint::disp(){ cout<<"x="<<m_x<<";y="<<m_y<<endl; } void CPoint::setXY(int x,int y){ m_x=x; m_y=y; } void func(CPoint &p){ //在一般函數中,參數是對象引用,通過對象引用調用成員函數 p.setXY(55,33); } int main() { CPoint p1(5,5),p2(25,25); p1.copy(p2); //把對象p2的地址賦值給對象引用 p1.disp(); func(p2); //把對象p2的地址賦值給對象引用 p2.disp(); return 0; }
對象數組(一串連續的對象)
舉一個例子來感受對象數組的聲明,初始化,和使用:

#include <iostream> #include<string.h> using namespace std; class CStudent{ public: CStudent(char *name,int age,int score);//構造函數 void disp(); private: char m_name[16]; //數據成員 int m_age; int m_score; }; CStudent::CStudent(char *name,int age,int score){ //構造函數的實現 strcpy(m_name,name); m_age=age; m_score=score; } void CStudent::disp() //顯示構造函數 { cout<<"name:"<<m_name<<";age:"<<m_age<<";score:"<<m_score<<endl; } int main() { CStudent csArray[4]={CStudent("srf",24,96),CStudent("dp",23,95), CStudent("aa",24,98),CStudent("bb",24,99)}; for(int i=0;i<4;i++) { csArray[i].disp(); //對象數組中的對象調用其成員函數 } return 0; }
子對象和堆對象的聲明和使用
一個類中的成員是另一個類的對象時,稱這個對象是子對象。換句話說,子對象就是類的對象成員。例如下面的橘子類(COrange)和蘋果類(CApple):

class COrange { public: COrange(); private: ... }; class CApple { public: CApple(); private: COrange orange; //橘子類的子對象 };
CApple的成員orange是類COrange的對象,所以orange為子對象。當一個類中包含子對象時,這個類的構造函數中應該包含對該子對象的初始化后。並且只能采用成員初始化表的方法來初始化該子對象。通過例子感受:
包含對象成員的類應用。

#include <iostream> #include<string.h> using namespace std; class COrange { public: COrange(int heft,int sweet); void disp(); private: int m_heft; int m_sweet; }; COrange::COrange(int heft,int sweet) { m_heft=heft; m_sweet=sweet; } void COrange::disp() { cout<<m_heft<<";"<<m_sweet<<endl; } class CApple { public: CApple(int heft,int sweet,int fragrant); void disp(); private: COrange orange; //聲明COrange類的子對象orange int m_fragrant; //數據成員--香味 }; CApple::CApple(int heft,int sweet,int fragrant):orange(heft,sweet) { //用成員初始化列表的方式初始化子對象,格式為:子對象名(參數表) m_fragrant=fragrant; } void CApple::disp(){ orange.disp(); cout<<m_fragrant<<endl; } int main() { CApple apple(8,18,28); //定義CApple類的對象apple apple.disp(); return 0; }
堆對象:用類定義的對象有一種特殊的對象,可以在程序運行時,隨時創建和刪除,滿足實時的程序要求,這種對象稱為堆對象。
因為這種對象的內存空間是創建在堆內存中,所以可以像堆空間一樣隨時申請和釋放,其操作符也是new和delete。
創建格式為:new 類名(參數名);
如:

CTest *p=NULL; //定義一個對象指針 p=new CTest(); //創建一個堆對象,並賦值給對象指針p
也可以創建堆對象數組

CTest *pa=NULL; pa = new CTest[5];
刪除時:

delete p; //p是一個指向new創建的堆對象的對象指針 delete [] pa; //pa是一個指向new創建的堆對象數組的對象指針
通過一個例子來感受對對象的創建,刪除和使用。

#include <iostream> #include<string.h> using namespace std; class CHeap { public: CHeap(); CHeap(int a,int b); ~CHeap(); void disp(); private: int m_a,m_b; }; CHeap::CHeap() { m_a=0; m_b=0; cout<<"調用默認的構造函數"<<endl; } CHeap::CHeap(int a,int b) { m_a=a; m_b=b; cout<<"調用帶參數的構造函數"<<endl; } CHeap::~CHeap() { cout<<"調用析構函數"<<endl; } void CHeap::disp() { cout<<"m_a="<<m_a<<";m_b="<<m_b<<endl; } int main() { CHeap *pheap; pheap=new CHeap(); //創建堆對象,並把地址賦值給pheap if(pheap) //判斷是否創建成功 { pheap->disp(); //通過對象指針,調用堆對象的成員函數 delete pheap; //刪除堆對象 } pheap = new CHeap(10,30); //把對象指針指向新的堆對象,使用參數構造。 if(pheap) { pheap->disp(); delete pheap; } return 0; }
堆對象如果創建失敗,new返回是NULL值,即空指針,所以使用前必須進行判斷,如果創建成功,則在最后不使用時,應當刪除這個堆對象,並釋放其占用的堆內存空間。
堆對象數組的創建,刪除,和使用,只看主函數部分的修改:

int main() { CHeap *pheap; pheap=new CHeap[3]; //把對象指針指向堆對象數組的首元素 if(pheap) //判斷是否創建成功 { for(int i=0;i<3;i++) { (pheap+i)->disp(); //調用對象數組中對象元素的成員函數 使用對象指針加增量來訪問對象數組中的每個對象元素 } delete []pheap; //刪除堆對象數組 } return 0; }
解析C++普通局部變量與指針類型的對象變量的應用區別
轉自:http://www.cnblogs.com/hellope/archive/2011/08/03/2126371.html
首先我們先來了解一下MFC中的CPtrArray類,他可以說是CObject類型指針對象的集合。通過int Add(CObject* newElement );注意參數是一個指針類型)可以向集合中添加元素。首先我們定義一個CPtrArray類型的對象。
CPtrArray pArray;//他是一個全局對象
先設定一個舉例的類類型。如:

class A { public: A(int i) { a = i; } ~A(){} public: int a; };
現在我們需要在某個函數中要實現將一個A類型對象數據加入到一個CPtrArray對象中。此函數func1()如下:

void func1() { //首先定義一個A類型的對象 A a(1); //使用pArray對象中的成員函數將此對象加入到容器中 pArray.Add(&a); }
在另一個函數中我們使用pArray容器為我們保存的數據:

void func2() { //首先聲明一個A類型的對象 A* a; //使用pArray對象中的成員函數GetAt()將A類型的對象取出 for(int i; i < pArray.GetSize();i++) { a = (A*)pArray.GetAt(i); //使用A中的數據進行相關的操作代碼。***此時也可以使用delete釋放指針指向的內存區塊,防止內存泄露***當然是后面一種方法時才用到,暫時無視之。 ... } }
現在我們發現按照上面的過程,當我們在func2()函數中將要使用pArray容器對象為我們保存的數據時,我們並不能得到想要的數據!!!為什么發生以上情況?圖解如下
pArray保存a保存資源的地址;
func1函數執行完成,a發生析構,資源不可用;
原來在func1()函數中,a對象是一個局部對象,當我們使用pArray.Add(&a);我們將a對象的地址保存到pArray對象中。但是作為局部對象,當func1
執行完成后,資源需要回收,此時我們定義的a對象也在A類中的析構函數中被析構釋放資源!而當我們在fun2()函數中執行取出保存的對象時,
實際是根據保存的地址去內存中找到數據,雖然此時我們能能夠找到此地址,但是這個地址上面的數據並不是我們需要的了!!!所以才發生面的情況!
那么怎么才能解決呢?
看下面,我們只需更改func1函數中的代碼:

void func1() { //首先定義一個A類型的對象 //A a(1);//為對比,只是注釋原來那句 A* a = new A(1); //使用pArray對象中的成員函數將此對象加入到容器中 pArray.Add(a); }
這樣,我們就能夠在func2函數中使用pArray對象中包含的數據了!那么為什么定義了一個指針類型的對象就能夠完成了呢?還是一個局部對象呀,
前面說的func1函數執行完成后此對象還是要經歷析構的啊!圖解如下:
pArray中保存a指向資源的地址;
func1函數執行完成,a對象發生析構,pArray根據地址還能能夠訪問到之前的資源;
對,是要析構,但是,我們在pArray.Add(a);中加入的是a對象資源的地址,我們先看看A* a = new A(1);在堆中分配資源,我們知道,在堆中分配的資
源是在跟程序的生命周期是一致的。a對象雖然析構了(不存在了),因為a也是一個指針,a指針也就是保存這個資源的地址!我們在pArray中保存
的a的地址出的資源並沒有析構!所以在func2函數中我們還能夠使用此地址訪問此地址對應的資源!