CLASS

来源:互联网 发布:阿里云app名师课堂在哪 编辑:程序博客网 时间:2024/06/07 14:15

This指针

  • this是一个隐含的内嵌指针,指向调用函数的对象
  • 选择直接输出this 默认是输出对象名
      this -> name =new char [ strlen(name) + 1 ]      *this = p2        // 也可以利用这种方式赋值

初始化一个新的对象

  • 什么都不做: 只写了一个Class(){ }或者什么都没写
      Invoice ( ) { } 建立对象之初NULL, 所有值完全由成员函数赋值
  • 建立的时候没有说明参数,完完全全通过公有成员函数完成初始化
       SetData(int a, int b)        1. 内联的方式  {para1=a ; para2=b}   类里面就给出定义        2.  Class : : SetData(para1=a ; para2=b) 类外通过加上 : : 给出定义        3. 调用时,Instance.SetData (a, b)完成调用  类外定义要与类声明在同一个cpp文件中                                                                //完全手动赋值,比较简单
  • 建立的时候没有说明参数,调用带有默认参数的构造函数
    Class Sale {        private: taxrate; totaltax;        public :  Sale(float total) {taxrate = 0.05;totaltax = total}    Sale cashier1;     默认cashier1的税率就是0.05                                                        //这样的好处是即使什么都不做也会有一定的初值
  • 利用指针初始化
    Invoice * ptr;   定义一个指向类对象的指针    ptr = new Invoice  指向一个新的对象的方式,但是没有赋值    ptr -> SetData(a,b)  通过成员函数手动完成赋值,                                                //这样的好处是在我们得到对象的时候还得到一个指针
  • 最常用:带值初始化
    Class Sale {    float  taxrate; totaltax;    public: Sale (float rate) {taxrate= rate}            Sale  (float rate,float total) {taxrate = rate,totaltax = total}                                    //一建立就立刻赋值,并且重载,根据情况决定一开始的值,其他的函数赋
  • 利用对象进行赋值(用默认的拷贝方法)
    Invoice p1(p2)  或者Invoice p1=p2;                        //p1与p2必须是同一类型 ,如果没有特别指定你的拷贝方式,会将变量甚至指针指向的地址都拷贝过去
  • 利用对象进行赋值,用你自己的拷贝方法
    Invoice (const Invoice& obj){  #拷贝函数用‘&’的原因,拷贝函数用const的原因        strcpy( taxrate, obj.taxrate )         name = obj -> name}                                            //这样可以避免把地址都给拷贝过去的情况,地址是可能被删掉的

由上,可以定义很多个构造函数互为重载关系,根据初始化给的什么值决定对象的情况,注意以下错误重载

Invoice () {ptr = new char [50]}Invoice () {int unit =80 ,ptr = new char [50]} 意味不明

析构函数

函数名=~+类名,无返回类型无参数

    Class Invoice        ~Invoice ()                 没有返回值类型,没有参数        {cout << "deconstructing"}   可以加一句话提醒正在解析
  • 析构函数会在很多时候发挥作用,实参形参结合的时候会调用拷贝构造函数
    • 如果函数结束,拷贝出来的临时对象也会被析构
  • 在构造函数里加上一个count++ ;析构函数里加上 - -;其中count是一个静态变量可以有效的统计当前对象的个数

静态成员函数

  • 同一个类中所有对象共享该变量 => 所有对象,一个变量
  • 静态数据 / 函数必须在类外定义与初始化,用: :指名所属的类, 并且不用写上Static关键字
  • 静态变量的生存周期与程序一样长
  • 建立对象之前就已经存在,就已经可以访问本类中其他的静态变量 / 静态函数
  • 静态成员函数无法使用this指针
    Class Invoice {        static int x;        public : static double area (int a, int b)}      //仅仅在类中做出声明    int Invoice :: x;                                  //初始化,定义全都在类外面完成    Invoice :: double area (int a ,int b){               //不写static 关键字        return a*b ;}
  • 静态成员调用方式 instance.x / instance.area(a,b)

FRIEND友元函数

  • 可以访问所有的私有 / 保护 / 公有成员

  • 外部函数作为类的友元 -可以访问所有成员

    Class Invoice {        int length;        friend double area (int a, int b)}      Invoice p1(3),p2(5);    area (p1.length, p2.length);            //friend以后就可以访问对象中的数据了
  • 类成员函数作为其他类的友元
    Class Budget;    Class Aux        void addbudget(float a, budget &);  //将要使用budget类的对象参数作为函数参数    Class Budget        friend void Aux::addbudget(float,budget&)  //允许Aux类add函数访问本类对象的参数
  • 这里面声明了两次class budget 第一次是作为超前使用说明
  • 一个函数可以是多个类的友元函数
  • 在类的内部定义的时候需要在前面加上关键字friend 而在外部定义的时候不需要加上关键字friend
  • 一个 类作为另一个类的友元就完全没有任何限制了,在数据层加上一个friend class B,不推荐
  • 友元函数也可以在类的内部定义

其他操作

  • 如果函数的形参是一个对象,则参数传递时会先调用拷贝构造函数,推荐使用 const Invoice & p ,不修改,不拷贝
  • 一个 非友元函数也可以使用对象作为形参,只是数据的获取要通过内部调用函数获得
  • 如果函数的返回值是一个对象,则函数执行结束,调用拷贝函数对无名返回值初始

继承

  • 子类不做任何改变的继承了父类中的所有变量与函数,除了构造函数与析构函数
    Class Test : public Grade 
  • 子类中现在一共有5个变量,包括有父类的三个以及自己的两个
    int a,int b;                  //这里的a与b是TEST类在Grade类基础上加上的性质    Test (int a,int b);            // 由于构造函数并没有被继承,因此需要另外加上构造    Test::Test (int q,int m) {q=a,m=b}   //类外描述定义
  • 子类的初始化:如果父类与子类都有构造函数的时候,定义一个子类对象会先调用父类的构造函数来初始化
    Class Rectangle (float w,float l)       //父类的构造函数    Class Cube (float,float,float)          // 子类的构造函数    Cube::Cube (float w,float l,float h):Rectangle (w,l)            height=h;length=l;width=w;      //类外给出子类析构函数的定义
  • 如果不调用父类的构造函数 = 没有显式调用 = 调用了缺省 = 定义了默认值就是默认值,否则就是全空
  • 如果父类,子类都有缺省的构造函数,那么定义子类的时候可以不调用父类的参数 - 对象属性全空
  • 类中的const常量仅在初始化列表中
   const int Size = 0;        //错误    Invoice::Invoice(int size):size(100)    //正确,这里是类外的定义区,将常量放到冒号后面的方式初始化

定义类中的常函数 / 常对象 / 常参数

  • 常函数的定义 type function( ) const / 调用 instance.function ( )
    • 常函数不修改任何对象instance内的任何内容,不小心修改会报错,代码更健壮
    • 通常只是为了展示instance对象的数据,因此也不需要任何参数
    • 一个常对象只能调用常函数,但是常函数可被任何对象调用
  • 常对象 const Invoice (a ,b)的方式初始化

问题:
- list<>* 是代表了这个list是指针还是list里面的内容是指针
- 优雅的调用list列表里面对象的函数

观察1.list<A*> a 与list<A>* a是不一样的,//想要表达一个list的对象请使用list<A*>      显而易见,此时的a是一个list对象,//调用函数也是通过list.push的方式进行案例1.    list<A*> aaa;    A* ptr = new A ();    aaa.push_back(ptr);     //因此list<A>* a的含义是a本身是一个指针,存放的不是指针,而是对象     
  • 通常情况下用到&是类对象函数,用来传另一个对象作为函数参数的,而在调用函数参数的时候加上&
案例1.  Authorisation(User *u, Workstation *w, int p, const StartSession &s, Directory *def)  //Authorisation auth(&will, &beast, 10, sess, &def)
  • list<>& 是怎么初始化的
首先没有一个叫做list<>&的概念,如果想使用一个List的引用,请使用list<A&>的用法其次,性质1.  引用的属性,使得他在初始化的时候就必须赋值    list<A&> a;的写法是不通过的,就是不通过的,那该怎么表示一些composition list

类函数声明,与跨文件实现
- Introduction:类的函数声明如果与函数实现放在同一个文件里,可能会有点烦人,阅读性不高

  • 怎么把类函数声明与函数体放在两个文件里呢?
1.假设A类的声明在A.h文件里,但是想把A类函数的函数体放到A_implementation.h文件2.在A_implementation.h 文件开头写上 #include "A.h"3.在main.cpp中同时    #include "A.h"                        #include "A_implementation.h"