【 C++ 类 】《 C++ Primer 》(读书笔记)

真棒

类的基本思想是 数据抽象封装。 数据抽象是一种依赖于 接口实现 分离的编程艺术。
类的接口包含 用户所能执行的操作; 类的实现则包含 类的数据成员,负责接口实现的函数体,以及各种私有函数。
类要想实现数据抽象和封装,需要定义一个抽象数据类型 。在抽象数据类型中,由类的设计者负责考虑类的实现过程,使用类的程序员则只需要抽象的思考类型做了什么,无需了解类的工作细节。

定义抽象数据类型

使用struct 或者class可以创建一个类,类里面包含成员变量,成员函数。如下:

class A {
	int func1(int a){
        printf("a=%d\n",a);
        printf("val=%d\n",val)
    }
    
    int val;
}

成员函数

定义在类内部的函数 是隐式的inline函数,一般情况成员函数在类内部声明,在类外部定义。

成员函数的参数列表后面跟一个const 关键字 是将 this指针的类型改为常量类型。
函数体内不改变this所指的对象,所以讲this修改为常量类型 有助于提高函数的灵活性。
常量对象,以及常量对象的指针或者引用都只能调用常量成员函数。

构造函数

类通过一个或几个特殊的成员函数来控制其对象的初始化过程,这些特殊的函数就是构造函数,构造函数的任务是初始化对象的数据成员,无论何时,只要类的对象被创建,就会执行构造函数。
如果类没有定义构造函数,编译器会创建一个 合成的默认构造函数。如果有自定义的构造函数,则不会创建默认的构造函数。
note: 只有当类没有声明任何构造函数时,编译器才会自动的生成默认构造函数。

拷贝初始化、赋值初始化 与 析构

当我们初始化的时候,以值的方式传递或者返回一个对象等,会发生拷贝操作。
当我们使用赋值运算符的时候,会发生赋值操作。
当对象不再存在,比如当一个局部对象所在块结束时,会被销毁,数组或容器中被销毁时,其中存储的对象也会被销毁。
要注意的是,如果类中有动态分配资源,这时默认的析构函数就不生效了,所以动态资源尽量使用 vector string map等容器。

访问控制与封装

定义在public 说明符后面的成员在整个程序中都是可以被访问的。
定义在private 说明符后面的成员 可以被类的成员函数访问,不能被类之外的其他代码访问。

class与struct 关键字

实际上定义类 上面两个关键字都可以使用,唯一的区别是struct和class的默认访问权限不同。
struct 关键字 定义在第一个说明符之前的 成员是public的
class 关键字 定义在第一个说明符之前的 成员是private的

一般情况 当我们希望定义的类所有成员都是public的,使用struct 反之如果希望是private的使用class。

友元

类可以允许其他类或函数访问它的非公有成员,方法是令其他类或函数称为它的友元。
类如果想把一个函数作为它的友元,只需要在类里面使用 friend关键字开头声明一下这个函数即可。
注意: 友元的声明 仅仅是指定了访问权限。并非一个通常意义上的声明。该函数还是要自己声明一次。
友元函数的函数体也可以定义在类的内部,但是还是要在 类的外部重新声明一下。不然,在类的内部也是不能调用友元函数的。
友元类也是一样,在一个类中使用friend声明 另一个类,另一个了就可以访问该类中的成员了。
同样,也可以让其他类中的一个成员函数 来作为当前类的友元函数,也是使用friend修饰一下。

类的其他特性

在类中定义一个类型成员
比如

class A {
public:
    /*下面这两种是等价的*/
    typedef std::string::size_type pos;
    using pos = std::string::size_type;  
private:
    pos a;
    pos b;
}

注意: 定义的类型成员要先定义再使用,这一点与普通成员有区别。

可以添加自定义构造函数来进行初始化对象。
可以将成员函数定义为内联函数,分为隐式内联和显式内联,隐式内联是在类里面实现函数体,显式内联是在类外面实现函数体,当然,类的内联成员函数也应该定义在类所在的头文件中。
重载成员函数
和非成员函数一样,成函数也可以被重载,
可变数据成员
这样的数据成员 也就是说 无论是正常的对象中,还是在const对象中都能修改的数据成员。
需要用 mutable 修饰该数据成员,然后就可以在const对象中修改。

类的作用域

一个类就是一个作用域。在外部使用一个类的成员时,必须跟上类的名字。因为类的成员对外是隐藏的,要先找到对应的类才能找到对应的成员。

我们编写程序的时候,如果要调用一个函数或者是变量,编译器会去寻找所用名字的最佳匹配声明

  • 现在名字当前块中寻找其声明语句,只考虑在名字使用之前的声明
  • 如果没有找到,继续查找外层的作用域。
  • 如果最终没有找到对应声明,程序报错。

内层作用域的对象或隐藏外层作用域的同名对象。

猜你喜欢

转载自www.cnblogs.com/heaikun/p/12749343.html
今日推荐