第六章 类与对象知识点简单整理

    1、 什么是类?

     面向对象系统由一组交互的对象构成,每个对象有自己的属性和行为,对象所属的类型成为类,类是对一组具有相同属性和行为对象的抽象。

     类的基本思想是数据抽象和封装。类可以具有数据成员,也可以具有成员函数。

     结构体内的函数被称为成员函数,结构体中的数据则称为数据成员。这样的结构体就是类,这种结构体类型变量被称为对象。

    2、定义类

    定义类的方法和定义结构体差不多,很多用法都和之前学习的struct结构体类似。

    

class X
{
private:
    int a;
    int b;
public:
    int c;
    int d;
protected:
    int e;
    int f;
};

其中public为公有成员声明,private为私有成员声明,protected为被保护成员声明。struct默认访问限制是public,且public在程序的任何函数或类中都可以被访问,但是private成员只能由类自己的成员函数或友元(可以访问私有成员,但是一般不建议使用,这样定义私有成员就没有意义了)访问,protected成员的访问全向介于public和private之间,它可以由类自己的成员函数,友元,派生类成员访问。注:如果class的成员没有设置访问限定符,则默认为private)类中也可以出现函数,比如

class X
{
private:
    int a;
    int b;
public:
    int c();
    int d;
protected:
    int e;
    int f;
};

这就可以通过访问限定符来对类进行封装,它的好处:

  1. 类内部的安全性与一致性加强
  2. 降低了客户程序员操纵该类型的复杂程度
  3. 类设计者改变类的内部工作方式时客户程序不受影响
  4. 经验之举是采用最严格的可行的访问级别
  5. 如果还不确定,多隐藏通常比少隐藏好

封装是指将数据和操作捆绑在一起,并加上访问限制。数据描述对象的属性,操作描述对象的行为。

    3、成员函数

    成员函数可以在类内定义也可以在类外定义,但成员函数在类外定义时,函数名字前面要加类名字和作用域符“::”,表示这个函数在其所属的类作用域内,是这个类的成员函数,不同于全局函数。

例如:

class X
{
private:
    int a;
    int b;
public:
    int c();
    int d;
protected:
    int e;
    int f;
};
int X::c()
{
    return a + b;
}

这就等同于

class X
{
private:
    int a;
    int b;
public:
    int c(){
      return a + b;
    }
    int d;
protected:
    int e;
    int f;
};

      4、this指针

    每个成员函数都有一个隐含的参数,指向接收消息的对象,即为this指针。

    X类的this指针的类型是X*

    this指针是一个常量,含有当前实施调用的对象的地址

    不能改变this指针的值,也不能取this指针的地址

     this指针在成员函数中的用途:

    区分与数据成员同名的变量

    返回当前对象

    取得当前对象的地址

    5、访问器和修改器

    将数据成员限定为private,并提供public成员函数来对其进行访问,这种成员函数被称为访问器(accessor)和修改器(mutator)

    常以一对getX()和setX() 函数的形式出现 一对重载函数的形式。

    6、友元

    这里就不详细的说明了,尽量不要使用,就大致的说一下用法把

    C++引入了friend关键字,如果想让非成员函数访问一个类中的私有数据,应该在类中将这个函数声明为friend 。

    一个类的友元可以访问该类的私有数据 在声明友元时要遵循一条规则: 友元必须在被访问的类中声明(重要)

    一个类的友元可以是

    1)全局函数

    2)另一个类的成员函数

    3)另一个类

         类A是类B的友元表示A的所有成员函数都是B的友元

    friend关系不可传递

    如果A是类B的友元,而类B是类C的友元,A不会自动成为C的友元

      注:应该尽量避免使用友元 友元会破坏类的封装性,增加类之间的耦合度

    7、构造函数

    构造函数在创建对象时被自动调用,负责初始化对象

    构造函数的名字和类名字相同,它没有返回类型

        是没有返回类型,不是返回void 类型

    构造函数的参数通常为数据成员提供初始值

    构造函数可以重载

       在创建对象时,编译器会根据初始值的类型和个数来调用相应的构造函数

       构造函数的形式决定了初始化对象的方式

    构造函数初始化

    类中有些成员不能使用赋值的方式提供初始值

        引用成员,const 数据成员,类类型的数据成员

    针对这种情况的特殊语法称为构造函数初始化列表

        成员1(初始值1)[,成员2(初始值2),…]

    初始化列表位于构造函数的参数表之后,函数体之前

        构造函数(参数表) : 初始化列表 { 函数体 }

    如:

class X {
int m, &r;
public:
X(int v):r(m) { m = v;}
};

    对比构造函数中为数据成员提供初值的两种方法

X(int v): r(m) { m = v;}		//①
X(int v): m(v), r(m) {}		//②

    在构造函数的函数体中,成员m先默认初始化,再在函数体中赋值

    写在初始化列表中,直接初始化数据成员,效率更高

    建议使用构造函数初始化列表语法

      如果成员是const、引用,或者是未提供默认构造函数的类类型,就必须通过构造函数初始化列表提供初值

X(int v = 0): r(m) { m = v;}		//①
X(int v = 0): m(v), r(m) {}		//②

    在初始化列表中,每个成员只能出现一次

    初始化的顺序与它们在类定义中出现的顺序一致

      1)初始化列表中初值排列的顺序不影响实际的初始化顺序

      2)如果可能的话,尽量避免用某些成员初始化其他成员

    委托构造函数(delegating constructor)

    委托构造函数使用所属类的其他构造函数执行自己的初始化过程,把部分或全部职责委托给了其他构造函数

    语法形式: ClassName(参数表):ClassName(参数表){函数体}

    8、析构函数

   1) 析构函数负责在对象生存期结束时返回相关资源和自动释放资源

    2)当对象离开作用域时,或者用delete 释放在堆上创建的对象时,析构函数都会被自动调用

    3)析构函数的名字是类名字前加波浪线“~”

    4)析构函数没有返回类型,也没有任何参数 析构函数不能重载,只能为一个类定义唯一一个析构函数

    5)析构函数主要被用来放弃在类对象的构造函数或生存期中获得的资源

              如释放互斥锁或归还new 分配的空间

    6)析构函数可以执行类设计者希望在最后一次使用对象之后执行的任何操作

    7)如果一个类只包含按值存储的数据成员,则析构函数不是必须定义的

             如果类中没有定义析构函数,编译器在需要时会自动合成一个析构函数。

    9、构造函数与析构函数的调用

    1)程序中无论以何种形式创建对象,都会调用构造函数

    2)各种初始化方式都会引起相应的构造函数调用

    3)堆上的对象,数组元素对象都要调用构造函数初始化

    4)当对象生命期结束时,则会调用析构函数

    5)析构函数绝大多数情况下都被自动地隐式调用,一般不要显式调用

    10、const成员

    const数据成员

    1)const 可以限定类中的数据成员,描述对象中的常量

    2)在数据成员声明前加const 关键字就将其限定为常量

    3)const 数据成员在构造函数的初始化列表中初始化

    4)创建对象时初始化其中的const 数据成员,之后const 成员的值在对象的整个生存期中都不会改变

   const成员函数

   1)类的对象也可以由const 限定为常量

             试图修改const 对象的操作会引起编译错误 (const对象不可修改)

             编译器可以轻易捕捉到对内置类型const 对象的修改

             类对象的变化更多是由成员函数的调用引起的

    2)将一个成员函数声明为const,表明这个成员函数不会修改对象的数据成员,能保证对象的常量性

    3)声明const成员函数的语法形式

             返回类型 成员函数名(参数表) const;

    4)定义const成员函数的语法形式

             返回类型 成员函数名(参数表) const { 函数体 }

    5)注意const成员函数声明和定义的语法

             对于在类外定义的const成员函数,必须在它的定义和声明中同时指定关键字const

    const成员函数的语法规则

    1)只有声明为const 的成员函数才可以被const 对象调用

    2)const 对象不能调用非const 成员函数 

             非const 对象可以调用const 成员函数

    3)const 成员函数中不能修改类的数据成员

    4)const 成员函数中不能调用其他非const 成员函数

    const 成员函数和对象的常量性

    为什么const对象不能调用非const成员函数?

             X 类的成员函数的隐含参数this 指针是X*类型

            const X 对象的地址是const X*类型

    const对象调用非const成员函数时

    1)形参this是X*类型

    2)实参即当前对象的地址是const X*类型

    3)编译器不能将实参const X*类型转换为形参类型X*,报告错误:参数类型不匹配

    const 在限定成员函数时对其参数表产生了影响

             const 限定的成员函数其实是将const 关键字作用于隐含的this 指针,其类型成为了const X*

    非const对象可以调用const成员函数

             形参this的类型const X*,实参类型X*,可以自动转换

    不能在const 成员函数中改变数据成员

            const 成员函数的this 指针是const X*类型,指向的对象是const,不能修改

    const 成员函数的定义和调用规则

    1)如果成员函数是非const 的,则只有非const 对象可以调用它;const 对象不能调用非const 的成员函数

    2)如果成员函数是const 的,则const 对象可以调用它;非const 对象也可以调用它,不会改变对象中的成员

    3)允许为成员函数定义const 和非const 两个版本,这两个版本是重载函数

             在这种情况下,对const 对象,会选择调用const 版本的成员函数;对非const 对象,则调用非const成员函数

    11、static成员

    static数据成员

    static数据成员被当作该类类型的全局变量

             对非static数据成员,每个对象都有自己的副本

             static数据成员对整个类类型只有一个,由这个类型的所有对象共享访问

    与全局变量相比,static数据成员有两个优点

           1)static数据成员没有进入成员的全局作用域,只是在类作用域中,不会与全局域中的其他名字产生冲突

            2)static成员仍然遵循访问控制规则 ,可以实现信息隐藏,static成员可以是private成员,而全局变量不能

    在类的数据成员声明前加关键字static,就使该数据成员成为静态的

    static数据成员的初始化

          1)static数据成员属于类,不属于某个特定对象,因而不能在构造函数中初始化

          2)static数据成员在类定义之外初始化,使用类名字限定 、

                      int Object::count = 0; 

    static成员只能定义一次

              定义一般不放在头文件中,而是放在包含函数定义的源文件中

    static数据成员可以是任何类型,甚至是所属类的类型

    static const数据成员

    可以用static const定义类中的常量

    static const 数据成员在类外初始化

    可以用static const定义类中的常量

             static const 数据成员在类外初始化

    static数据成员的访问

    在类的成员函数中可以直接访问static数据成员   

    在非成员函数中通过两种方式访问static数据成员

          成员访问运算符“.”或“->”

               像访问普通数据成员的语法一样,通过对象或指针来访问

    类名限定的静态成员名

         static成员只有一个副本,可以直接用类名字限定的静态成员名字访问

         ClassName::StaticMemberName

    注意:static成员仍然遵循访问控制的约束

    static成员函数

    一般需要通过成员函数来访问数据成员

    成员函数也可以访问static数据成员

           普通成员函数必须通过类的对象或指针调用,而静态数据成员并不依赖对象存在

          如果成员函数只访问静态数据成员,那么用哪个对象来调用这个成员函数都没有关系,因为调用的结果不会影响任何对象的非静态数据成员

    可以将这样的成员函数声明为static成员函数

    声明语法是在类定义中的函数声明前加static 关键字

         在类外定义时不需要加关键字static

    12、指向成员的指针

    成员指针

    指针是保存内存地址的变量,既可以是数据的地址也可以是函数的地址

    成员指针遵从同样的概念,只是指向的是类的成员

    问题:如何定义和使用指向成员的指针?

    类内部的成员是没有地址的,只有把成员在类中的偏移和具体对象的起始地址结合在一起才能得到实际的地址

    使用数据成员指针的语法

            如果有一个指向类成员的指针p,要取得指针指向的内容,必须用“*”运算符解引用

           *p是一个类的成员,不能直接使用,必须指定对象或指向对象的指针来选择这个成员

            使用指向数据成员的指针的语法应该如下:

                 对象.* 指向成员的指针

                 对象指针 ->* 指向成员的指针

    定义指向数据成员的指针

       指定指针指向的类型,说明它指向的是哪个类的成员

       语法形式 成员类型 类名字::*指向成员的指针;

       例如:int Simple::*pa;

               定义了一个指向Simple类中的int成员的指针,它可以指向Simple类中的任何int成员

 

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值