• c++ 吕凤翥 第六章 类和对象(二)


    c++ 吕凤翥 第六章 类和对象(二)

      指针   引用  和数组

    一:对象指针和对象引用

     1.指向类的成员的指针

      分为指向成员变量和指向成员函数两种指针

      成员变量的格式:      类型说明符  类名:: * 指针名

      成员函数的格式:   类型说明符  (类名::* 指针名)(参数表)

        class A

      {

        public:

          int fun(int b){return ...}

          A(int i){a=i;}

          int c;

        private:

          int a;

    }

      定义指向类A 的数据成员c的指针pc  :    int A::*PC=&A::c;     此时c为公有成员

      定义指向类A的成员函数fun的指针pfun:int (A::*pfun)(int)=A::fun;      函数名为地址   所以未用取地址符号   fun也是公有成员函数  所以可以直接指向

      先创建对象,然后通过对象来引用指针指向的成员

      A a;

      a.* pc=8;

      使用指向对象的指针通过指向类成员的指针对该成员进行操作时,可以使用运算符->*    运算符前面为指向对象的指针,后面为指向类成员的指针

        A * p=&a;  //a   为A类的对象     p是指向对象a的指针

        p->*pc=8;  //pc为指向A类的成员c的指针

      指向普通函数的指针的声明格式:(非类中的成员函数)

                                   类型说明符    *     指针名   (参数表)

         赋值格式:        指针名  =函数名        即指针变量的值为函数名即地址

           调用格式:     (* 指针名)(实参表)

       如果是指向类的成员函数的指针    则应加上相应的对象名指向对象的指针名以及对象成员运算符。 

       案例:

        

    //吕 example 6.1
    #include <iostream>

    using namespace std;

    class A
    {
    public:
    A(int i){
    a=i;
    }
    int fun(int b)
    {
    return a*c+b;
    }
    int c;
    private:
    int a;
    };

    int main()
    {
    A x(8); //构造
    int A::*pc;// pc指向类A
    pc=&A::c;//pc指针初始化 为公有成员c
    x.*pc=3; //成员变量赋值
    int(A::*pfun)(int);//指向成员函数的指针声明
    pfun=A::fun;//初始化指向成员函数的指针
    A*p=&x; // 声明 初始化指向对象的指针
    cout<<(p->*pfun)(5)<<" ";
    }

    上例中   指针的性质是不同的   p指向对象        pc和pfun是指向类中的成员

    2.对象指针和对象引用作为函数参数

      使用对象指针做函数参数更加普遍   

      特点:

      1.传地址调用   可改变实参的值(被调函数中改变调用函数中的参数值),实现函数之间的信息传递

      2.使用对象指针作为形参仅将对象的地址值传给形参,而不进行对象副本的复制(函数传值的方式 )   提高运行效率,减少开销

      传递的实参必须是对象的地址

    案例2:

    //吕6.2 example

    #include <iostream>
    using namespace std;
    class M
    {
    public:
    M() //default c
    {
    x=y=0;
    }
    M(int _x,int _y) //c
    {
    x=_x;
    y=_y;
    }
    void copy(M * m); //member #1
    void setxy(int _x,int _y) //member #2
    {
    x=_x;y=_y;
    }
    void print() //member #3
    {
    cout<<x<<","<<y<<" ";
    }
    private:
    int x,y;
    };

    void M::copy(M * m) //implementation m为指向M对象的指针
    {
    x=m->x;
    y=m->y;
    }

    void fun(M m1,M * m2); //function prototype 非类中的函数

    int main()
    {
    M p(5,7),q;//两个对象 一个非默认 一个默认
    q.copy(&p);
    fun(p,&q);//p的值不变 传递的是副本 q的值变化 传递的是对象的地址
    p.print(); //5 7
    q.print(); //22 25
    return 0;
    }

    void fun(M m1,M * m2)//使用对象指针作为参数 传递
    {
    m1.setxy(12,15);
    m2->setxy(22,25);
    }

    2.对象引用作为函数参数

      使用对象引用做参数比指针更加的普遍    用引用更加方便  更加直接

      example 6.3   

      与6.2的区别

      void copy(M &m);    //&取代了*

      void fun(M m1,M & m2);

    3.this 指针

      this  是一个由系统自动提供的指向对象的特殊指针。   该镇值是一个指向 正在对某个成员函数操作的对象的指针。

      当对一个对象调用成员函数时,编译器先将该对象的地址赋值给系统创建的this指针。然后再调用成员函数,每次成员函数存取数据成员时,都会隐含着使用this指针。同样适用*this 来标识  调用该成员函数的对象。

      案例:6.4 

       

    //example 6.4 吕
    #include <iostream>
    using namespace std;
    class A
    {
    public:
    A(){
    a=b=0;
    }
    A(int i,int j)
    {
    a=i;b=j;
    }
    void copy(A &aa);//其中的&为引用
    void print()
    {
    cout<<a<<","<<b<<" ";
    }
    private:
    int a,b;
    };

    void A::copy(A &aa)
    {
    if(this==&aa) return; //其中的&为取地址运算符 成员函数中的this的值为aa对象的地址
    * this=aa; //将aa对象中的成员值 赋值给this指向的对象 ,对象间的赋值
    }

    int main()
    {
    A a1,a2(3,4); //初始化两个对象
    a1.copy(a2); //用a2来赋值a1
    a1.print();
    return 0;
    }

    6.4对象数组和对象指针数组

    1.对象数组

      数组中元素为对象的数组   需要都是同一个类的对象

      类名    数组名    [大小]

      DATE   dates [10];        一维数组

      DATE   dates [10][5];    二维数组

    2.对象数组的赋值

      对象数组可以赋初值   也可以赋值

      DATE(int m,int d,int y),    //构造函数

      DATE  dates[3]={DATE(1,2,3),DATE(4,5,6),DATE(7,8,9)};      初始化

      dates[0]=DATE(7,22,1998);      对数组中的某个成员赋值

    案例:

      

    //example 6.5 吕
    #include <iostream>
    using namespace std;
    class DATE
    {
    public:
    DATE()
    {
    month=day=year=0;
    cout<<"default called. ";
    }
    DATE(int m,int d,int y)
    {
    month=m;
    day=d;
    year=y;
    cout<<"constructor called ";
    }
    ~DATE() //析构函数
    {
    cout<<"destructor called. ";
    }
    void print()
    {
    cout<<"month="<<month<<";day="<<day<<";year="<<year<<" ";
    }
    private:
    int month,day,year;

    };

    int main()
    {
    DATE dates[5]={DATE(7,22,1998),DATE(7,23,1998),DATE(20,11,2003)}; //头三个元素用非默认构造函数初始化;后两个用默认的构造函数初始化
    dates[3]=DATE(7,25,1998); //非默认构造函数来更改数组元素的值
    dates[4]=DATE(1,7,2003); //同上    
    for(int i(0);i<5;i++)
    dates[i].print();
    return 0;
    }

    上面的dates[3]     先用构造函数创建一个无名的对象,然后将它赋值给数组元素  ,然后再将无名对象通过调用析构函数来实现。

    6.2指向数组的指针和指针数组

      1.指向数组的指针

      类型说明符    (* 指针名) [大小]

      int (* P)[3];    //   int型  3个元素组成的数组    p为指针  指向这个数组

      

      类名   (* 指针名) [大小]

      类名  (* PL)[4];  //PL为指针名   指向包含4个对象元素的数组

      

      

    //example 6.6 

    #include <iostream>

    using namespace std;

    int a[][3]={1,2,3,4,5,6,7,8,9};//列表初始化
    int main()
    {
    int (*pa)[3](a);//声明数组包含3个元素  每个元素为指向整型的指针类型     初始化pa为a    a为二维数组的地址
    for(int i=0;i<3;i++)
    {
    cout<<" ";
    for(int j=0;j<3;j++)
    cout<<*(*(pa+i)+j)<<"";    //*pa   第一次解引用   从二维数组降到一维数组         *(*pa)  从一维降到数组中的单个元素   所以输出的是元素的值
    }
    cout<<" ";
    return 0;
    }

     pa为指向数组a的第0行一维数组的指针    

    注意:指向一维数组的指针都用二维数组的某个行地址(即该行首地址)赋值。

     6.7    指向对象数组的指针

    //exmaple 6.7 
    #include <iostream>
    using namespace std;
    class M
    {
    public:
    M(){
    a=b=0;
    }
    M(int i,int j)
    {
    a=i;b=j;
    }
    void print()
    {
    cout<<a<<","<<b<<' ';
    }
    private:
    int a,b;
    };

    int main()
    {
    M m[2][4];          //二维数组   元素为M类对象    数组名为m
    int x=10,y=10;
    for(int i=0;i<2;i++)  
    for(int j=0;j<4;j++)
    m[i][j]=M(x+=2,y+=10);    //初始化 对象数组
    M(*pm)[4](m);//         //声明 指向数组的指针   指针指向的数组元素为M类的对象      二维数组名代表地址  赋值给pm[0]  

                   //定义一个指针 指向对象数组的指针pm     用二维m的数组名来初始化     pm指向二维数组m的首行
    for(int i=0;i<2;i++)
    {
    cout<<" ";
    for(int j=0;j<4;j++)
    (*(*(pm+i)+j)).print();    //两次解引用 从二维变为一维   再从一维变为数组中的元素   M类的对象
    }
    cout<<" ";
    return 0;
    }

    2.指针数组

    数组元素为指针的数组称为指针数组。一个数组的元素可以是指向同一个类型的一般指针,也可以是指向同一类类型的对象指针

      类型名   *   数组名   [大小]    

    表示该数组名中的元素为指针

    int  *  pa[3];       //包含3个元素  每个元素是一个int型的指针  

    char  *  pa[2][5];    //包含10个元素  每个元素是一个char型的指针

    //example 6.8 吕 指针数组 元素为指针

    #include <iostream>
    #include <string.h>    //此时需要加.h   没有h   编译器找不到函数

    using namespace std;
    const int N=5;        //全局常量
    int main()
    {
    char * strings[N];       //声明一个指针数组      元素为指向字符串的指针
    char str[80];        //声明一个字符串数组
    cout<<"At each prompt,enter a string: ";  
    for(int i=0;i<N;i++)
    {
    cout<<"Enter a string #"<<i<<":";
    cin.getline(str,sizeof(str));    //获取一行输入中  实际输入长度字符串的首地址  赋值给str
    strings[i]=new char[strlen(str)+1];  //开辟一个长度比输入的字符串长度+1的数组   将首地址赋值给指针数组的对应元素(字符串指针)
    strcpy(strings[i],str);      //将输入进来的字符串赋值拷贝到新开辟的位置的数组,并且通过字符串指针来访问呢
    }
    cout<<endl;
    for(int i=0;i<N;i++)
    cout<<"string #"<<i<<":"<<strings[i]<<endl;    //输出指针数组中各个元素指向的字符串
    return 0;
    }

    所有数组元素都是指向同一个类类型的对象的指针 

     类名  *  数组名  [大小]

     //example 6.9 吕

    #include <iostream>
    using namespace std;
    class A
    {
    public:
    A(int i=0,int j=0){
    a=i;b=j;
    }
    void print();//声明带分号 实现不用分号
    private:
    int a,b;
    };//类的声明 加上分号
    void A::print()
    {
    cout<<"a="<<a<<";"<<"b="<<b<<" ";
    }

    int main()
    {
    A a1(7,8),a2,a3(5,7); //调用不同的构造函数 初始化
    A *b[3]={&a3,&a2,&a1}; //列表初始化指针  指针数组
    for(int i=0;i<3;i++) //
    b[i]->print();
    }

     6.2   带参数的main函数

    void  main(int argc,char * argv[])    

    其中   argc是代表命令行参数的个数 (包括命令本身也计数)    argv  数组包含参数的实际内容    命令本身也包含在内

       argv[0]  命令字

       argv[1]  命令行第一个参数

       argv[2]  命令行第二个参数

      ...

    //example 6.10 
    #include <iostream>
    using namespace std;
    int main(int argc,char * argv[])
    {
    cout<<"the number of command line arguments is"<<argc<<endl;
    cout<<"the program name is "<<argv[0]<<endl;   //打印程序名
    if(argc>1)  
    {
    cout<<"the command line arguments: ";  //
    for(int i=0;i<argc;i++)    
    cout<<argv[i]<<endl;           //  打印从1开始的参数内容
    }
    return 0;
    }

    6.3常类型

    用const来说明     对象或者变量的值是不能被更新的      所以定义或说明常类型量时必须进行初始化

    int const m=15;

    m=18;    //此语句错误   因为前面已经初始化了m值  不能再修改

    6.3.1 一般常量和对象常量

      int const  x=2;    //const  可以如此   也可以位于int之前

      类型说明符    cosnt   数组名  [大小]=初始值

      const   类型说明符    数组名  [大小]=初始值

      int const a[5]={1,2,3,4,5};//数组元素的值是不能被更新的。

    2.常对象

      常对象是指对象常量,定义格式:

      类名   const   对象名   (初始值)    

         初始化后对象不能被更新    同样const的位置可以变化

    6.3.2  常指针和常引用

      1.常指针

      常指针使用修饰符const说明      一种表示指针的地址值是常量   另一种表示指针所指向的是常量   格式不同

      类型   *   const  指针名=初始值     表示指针是常量   即   指针的值 (实际的地址)  不可以被修改  ;但是指向(实际内存地址处)的值可以被修改。

        char * const ps1=s1;     ps1的值是不变的     始终为s1          *ps1   可以改变 

          ps1=s2    是非法的

          * ps1=“char”  指针所指向的值是可以改变的      将char 字符串存入ps1的地址处

      2.所指向的值是常量的常指针

      这是一种指向某类型常量的指针   它定义的格式如下:

      const   类型   *   指针名=初始值

      const  char  *   ps2=s2;

      ps2  是一个常指针    指向的量是常量   不能改变   但是该指针的地址值是可以改变的

      3.常引用

      使用const修饰符可以说明引用   被说明的引用为常引用  该引用所引用的对象不能被更新。

      const    类型说明符   &  引用名= 初始值

      double b(1,2);

      const double & v=b;

      v=a;    //此语句非法

      c++中   常指针和常引用往往用来作为函数的形参,这样的参数称为常参数。使用const修饰的常指针和常引用更多

      好处是参数传递过程中不必执行复制构造函数   会改善程序的运行效率

    //6.11 example const pointer as argument

    #include <iostream>
    using namespace std;

    const int N=5;        //const修饰的常量
    void print(const int * p,int n);//函数原型

    int main(int argc,char * argv[])
    {
    int array[N];
    for(int i=0;i<N;i++)
    cin>>array[i]; //将标准输入到数组中 以单个字符输入
    print(array,N); //打印数组中的各个元素         //传递实参
    return 0;
    }

    void print(const int *p,int n) //函数实现       //形参接受     注意接收的方式  
    {
    cout<<"{"<<*p<<endl; //打印数组中的第0个元素
    for(int i=1;i<n;i++)
    cout<<","<<*(p+i)<<endl;//打印数组中其他的元素
    cout<<"}"<<" ";
    }

    //6.12  常引用作为函数的参数

     

      

      

      

      

      

  • 相关阅读:
    XPath在python中的高级应用
    Python中 sys.argv[]的用法简明解释
    python format
    爬虫解析:XPath总结
    c#attribute特性
    .net随笔--不好归类的
    windows系统操作
    linux学习
    visual studio各种新建项目和新建项简介
    自定义界面和控件--基础
  • 原文地址:https://www.cnblogs.com/dongguolei/p/9810340.html
Copyright © 2020-2023  润新知