• C++ 类对象和 指针的区别


    C++ 类对象和 指针的区别

    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;
    }
    View Code

    对象的情况:

    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;
    }
    View Code

    类的对象和类的指针的区别

    转自: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; // 调用静态数据成员 
        } 
    }; 
    View Code

    类对象: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; 
    } 
    View Code

    对于类student ,定义了一个对象 和一个指针。

    类的指针:他是一个内存地址值,他指向内存中存放的类对象(包括一些成员变量所赋的值).   
    对象,他是利用类的构造函数在内存中分配一块内存(包括一些成员变量所赋的值).   
              在应用时:   
            1.引用成员:   对象用"   .   "操作符;   指针用"   ->   "操作符.   
            2.生命期:     若是成员变量,则是类的析构函数来释放空间;若是函数中的临时变量,则作用域是该函数体内.而指针,则需利用delete   在相应的地方释放分配的内存块.   
    注意:用new   ,一定要delete..

    类的对象:用的是内存栈,是个局部的临时变量.   
    类的指针:用的是内存堆,是个永久变量,除非你释放它.   
        
    当类是有虚函数的基类,Func是它的一个虚函数,则调用Func时:   
    类的对象:调用的是它自己的Func;   
    类的指针:调用的是分配给它空间时那种类的Func;  

    对于一个类的对象和这个类的指针(用new运算符分配内存)在应用时有何区别   
    1.类和对象是两回事,对象是类的实例;   
    2.对象是在栈中分配的,使用new生成的对象是在堆中分配的;   
    3.要发挥虚函数的强大作用,必须使用指针来访问对象.  

    指针可以实现多态,直接用对象不行 
    执行定义对象,在栈空间 
    new的在堆

    类型决定了你能做什么.

    其实作用基本一样 都是为了调用类的成员变量 和成员函数用的 
    当你希望明确使用这个类的时候,最好使用对象,如果你希望使用C++中的动态绑定,则最好使用指针或者引用 
    指针和引用用起来更灵活,容易实现多态等

    1.在类的声明尚未完成的情况下,可以声明指向该类的指针,但是不可声明该类的对象... 
    2.父类的指针可以指向子类的对象..

    定义对象实例时,分配了内存。指针变量则未分配类对象所需内存,除非new了

    指针变量是间接访问,但可实现多态(通过父类指针可调用子类对象),并且没有调用构造函数。 
    直接声明可直接访问,但不能实现多态,声明即调用了构造函数(已分配了内存)。 
    至于那个效率高要看程序调用过程而定。

    C++的精髓之一就是多态性,只有指针或者引用可以达到多态。对象不行

    用指针: 
    第一实现多态。 
    第二,在函数调用,传指针参数。不管你的对象或结构参数多么庞大,你用指针,传过去的就是4个字节。如果用对象,参数传递占用的资源就太大了

    C++类和对象

    转自: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;
    View Code

    示例如下:

    class Object {
    public:
        Object();
        ~Object(); //must be public
        Object(int num);
        int getNumber();
        void setNumber(int num);
                        
    private:
        int m_num;           
    };
    View Code

    如何定义一个已声明的类:

    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;
    }
    View Code

    如何实例化和使用一个类:

    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
    ", obj1.getNumber());
        printf("obj2.getNumber() = %d
    ", obj2.getNumber());
        printf("obj3.getNumber() = %d
    ", obj3.getNumber());
        printf("pObj4->getNumber() = %d
    ", pObj4->getNumber());
        printf("pObj5->getNumber() = %d
    ", pObj5->getNumber());
        for (int i = 0; i < 10; i++) {
            printf("objs[%d].getNumber() = %d
    ",i, objs[i].getNumber());
        }
        delete pObj4;
        delete pObj5;
        return 0;
    }
    View Code

    struct 和union的类声明

    类可以定义不仅可以用关键字class,也可以用关键字struct和union。

    class和struct的概念是相似的,可用struct和class声明C++的类(即struct可以有数据成员和函数成员)。两者之间唯一的区别是使用关键字struct声明的类成员默认情况下,是public访问权限,而使用关键字class声明的类成员默认是private访问权限。对于所有其他的目的,这两个关键字是等价的。

    union的概念是与struct和class声明类不同的,因为union一次只能存储一个数据成员,但union也可能拥有函数成员,union类的默认访问权限是public。

    C++新特性(类与对象的各种指针和引用)

    转自: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;
    }
    View Code

    对象引用作为函数参数:比把对象指针作为函数参数更为普遍,因为使用对象引用作为函数参数不仅具有对象指针的优点,而且使用对象引用更为直观和简单。所以在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;
    }
    View Code

    对象数组(一串连续的对象)

    举一个例子来感受对象数组的声明,初始化,和使用:

    #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;
    }
    View Code

    子对象和堆对象的声明和使用

    一个类中的成员是另一个类的对象时,称这个对象是子对象。换句话说,子对象就是类的对象成员。例如下面的橘子类(COrange)和苹果类(CApple):

    class COrange
    {
        public:
            COrange();
        private:
            ...
    };
    class CApple
    {
        public:
            CApple();
        private:
            COrange orange;              //橘子类的子对象
    };
    View Code

    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;
    }
    View Code

    堆对象:用类定义的对象有一种特殊的对象,可以在程序运行时,随时创建和删除,满足实时的程序要求,这种对象称为堆对象。

    因为这种对象的内存空间是创建在堆内存中,所以可以像堆空间一样随时申请和释放,其操作符也是new和delete。

    创建格式为:new 类名(参数名);

    如:

    CTest *p=NULL;   //定义一个对象指针
    p=new CTest();    //创建一个堆对象,并赋值给对象指针p
    View Code

    也可以创建堆对象数组

    CTest *pa=NULL;
    pa = new CTest[5];
    View Code

    删除时:

    delete p;           //p是一个指向new创建的堆对象的对象指针
    delete [] pa;          //pa是一个指向new创建的堆对象数组的对象指针
    View Code

    通过一个例子来感受对对象的创建,删除和使用。

    #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;
    }
    View Code

    堆对象如果创建失败,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;
    }
    View Code

    解析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;
    };
    View Code

    现在我们需要在某个函数中要实现将一个A类型对象数据加入到一个CPtrArray对象中。此函数func1()如下:

    void func1()
    {
        //首先定义一个A类型的对象
        A a(1);
        //使用pArray对象中的成员函数将此对象加入到容器中
        pArray.Add(&a);
    }
    View Code

    在另一个函数中我们使用pArray容器为我们保存的数据:

    void func2()
    {
        //首先声明一个A类型的对象
        A* a;
        //使用pArray对象中的成员函数GetAt()将A类型的对象取出
        for(int i; i < pArray.GetSize();i++)
        {
            a = (A*)pArray.GetAt(i);
            //使用A中的数据进行相关的操作代码。***此时也可以使用delete释放指针指向的内存区块,防止内存泄露***当然是后面一种方法时才用到,暂时无视之。
            ...
        }
         
    }
    View Code

    现在我们发现按照上面的过程,当我们在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);
    }
    View Code

    这样,我们就能够在func2函数中使用pArray对象中包含的数据了!那么为什么定义了一个指针类型的对象就能够完成了呢?还是一个局部对象呀,

    前面说的func1函数执行完成后此对象还是要经历析构的啊!图解如下:

    pArray中保存a指向资源的地址;

    func1函数执行完成,a对象发生析构,pArray根据地址还能能够访问到之前的资源;

    对,是要析构,但是,我们在pArray.Add(a);中加入的是a对象资源的地址,我们先看看A* a = new A(1);在堆中分配资源,我们知道,在堆中分配的资

    源是在跟程序的生命周期是一致的。a对象虽然析构了(不存在了),因为a也是一个指针,a指针也就是保存这个资源的地址!我们在pArray中保存

    的a的地址出的资源并没有析构!所以在func2函数中我们还能够使用此地址访问此地址对应的资源!

  • 相关阅读:
    linux 清空文件内容命令
    优秀的java 社区
    vue强制刷新组件 ----组件重置到初始状态
    function的json对象转换字符串与字符串转换为对象的方法
    js实现深度优先遍历和广度优先遍历
    Egg.js中使用sequelize事务
    JavaScript ES6 数组新方法 学习随笔
    eggjs的参数校验模块egg-validate的使用和进一步定制化升级
    Node.js 服务端图片处理利器
    webp图片实践之路
  • 原文地址:https://www.cnblogs.com/flylong0204/p/4731318.html
Copyright © 2020-2023  润新知