C++ 類對象和 指針的區別html
轉自: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; }
對象的狀況:app
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; }
類的對象和類的指針的區別ide
轉自: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工具
很關鍵的一點:定義對象實例時,分配了內存,指針變量則未分配類對象所需內存。post
類的指針:他是一個內存地址值,他指向內存中存放的類對象(包括一些成員變量所賦的值).
對象,他是利用類的構造函數在內存中分配一塊內存(包括一些成員變量所賦的值). url
指針變量是間接訪問,但可實現多態(經過父類指針可調用子類對象),而且沒有調用構造函數。
直接聲明可直接訪問,但不能實現多態,聲明即調用了構造函數(已分配了內存)。
類的對象:用的是內存棧,是個局部的臨時變量.
類的指針:用的是內存堆,是個永久變量,除非你釋放它.
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; }
類能夠定義不只能夠用關鍵字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
對象與函數的關係(知道如何把對象指針和引用做爲函數參數)
將對象指針做爲函數的參數,傳遞給函數處理有兩個好處
一、減小數據分配的時間和空間,提升了程序運行的效率;
二、在被調函數中,能夠直接改變實參對象的值,實現函數之間的信息交換。
經過一個例子感覺 對象指針做爲函數的參數
#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; }
轉自: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函數中咱們還可以使用此地址訪問此地址對應的資源!