• C++笔记——类(0)定义、访问控制、友元、default、mutable、构造函数


    整理一下一些关于类的知识点,毕竟还是很经常用的(先总结一部分,太多了)。

    定义格式、访问控制

    C++里面定义类的关键词有两个,一个是class,另一个是struct,他们基本没有区别,除了成员变量的默认属性。在class中,默认属性为private,而在struct中,默认为public。但是通常编程的时候都会将struct视为数据的集合(类似C语言中的那样),而不会用作类。

    直接举个例子说明:

    class point{
    public:
        void setPoint(intx, inty);
        void printPoint();
    private:
        int xPos;
        int yPos;
        // 这里可以声明成员函数,例如void xxx();
    };
    

    public修饰下的可以在整个程序内被访问,private只能够在类里面访问(上面的例子里private下只有成员变量,其实还可以有成员函数,如果是成员函数的话则只能被类里的其他成员函数调用,没办法在类外面调用)。

    用访问说明符的目的就是封装,通过publicprivate的区分,我们可以将具体实现、数据放在private中禁止用户访问,强制让用户去使用public中定义好了的对外开放的接口。其实搞这么个东西出来主要目的就是隐藏实现具体的细节。

    而且,封装可以带来两个好处:

    1. 确保用户代码不会无意间破坏封装对象的状态
    2. 被封装的类的具体实现细节可以随时改变,无须调整用户级别的代码(虽然类的定义变了之后用户不用调整代码,但是还是要重新编译)

    另外,上面类里面其实只是声明了函数,还没有给定定义,通常类的声明会放在xx.h这样的头文件中,方便用户使用,而类里面的函数定义会放在xx.c中,具体写法大概可以总结成这样:

    #include "xx.h" // 类的头文件,以下内容保存在"xx.c"中
    using namespace std;
    
    void point::setPoint(int x, int y) {
        xPos = x;
        yPos = y;
    }
    
    void point::printPoint() {
        cout << "x = " << xPos << endl;
        cout << "y = " << yPos << endl;
    }
    

    注意声明命名空间point::,不然就不是在为类的成员函数定义了,而是直接定义了一个普通的函数。

    不过注意的是,通常如果是在类里面定义函数的话,默认是内联函数,而外部定义,如果想要定义为内联函数则需要加上inline关键词来修饰函数定义:

    inline void point::setPoint(int x, int y) {
        xPos = x;
        yPos = y;
    }
    

    在使用类的成员函数的时候要记得加上类的名字,例如:

    point::setPoint(2, 3);
    

    friend,友元的魔法

    class point{
    friend point copyPoint();
    public:
        void setPoint(intx, inty);
        void printPoint();
    private:
        int xPos;
        int yPos;
    };
    point copyPoint() {
        // ...省略
    }
    

    友元只是指定了访问的权限,而不是函数声明。所以如果希望用户能够调用这个函数,那么就要在友元声明之外再专门对函数进行一次声明(通常这种声明就放在定义类的头文件里面)。被声明为友元的函数可以访问类内部的private成员变量/函数。当然,除了可以声明函数为友元,还可以声明类为友元,这里就不举例子了。

    可变数据成员

    有时候我们会希望能够修改类的某个用const修饰过的只读成员函数中的数据成员,例如,用来记录这个函数被调用了多少次。这时候就需要在变量的声明中加入mutable关键字。

    class screen {
    public:
        void someMember() const; // 这个是只读成员函数
    private:
        mutable size_t accessCtr;
    };
    
    void screen::someMember() const
    {
        ++accessCtr;
    }
    

    上面函数声明后面加const代表声明的函数是只读函数,只读函数通常只能够读取类里面成员函数的值,而不能够修改他们,除非成员函数前有mutable来修饰,这样即使是在只读成员函数中这个成员变量的值也可以被修改。

    构造函数

    其实默认情况下,如果你没有专门定义另外的构造函数的话,编译器会默认生成一个默认的构造函数给你定义的类,来初始化类里面的变量。

    class ex{
    private:
        int a;
        int b;
        float c;
    };
    

    构造函数就是和类同名且没有返回值的函数,在用类创建对象的时候就会调用构造函数来给对象赋初始值。构造函数可以不止一个,因为可以重载,但是前提是满足实现重载需要的条件(类里面的函数都可以重载)。

    class ex{
    public:
        // 类里面可以有多个构造函数
        ex();
        ex(int d);
        ex(int e, float f):b(e), c(f) { }; // 这里使用了初始值列表,相当于是直接将b初始化为e的值,c初始化为f的值
                                           // 因为是直接初始化所以比初始化后赋值,即在函数体内写b=e这种方式效率更高
    private:
        int a;
        int b;
        float c = 0.0;    // 顺带一提,可以这样给类的成员变量赋初始值
    };
    

    值得注意的是,一旦声明了一个构造函数,则默认的构造函数会失效,例如:

    class ex2{
    public:
        ex2(int e, float f):b(e), c(f) { };
    private:
        int a;
        int b;
        float c = 0.0;    // 顺带一提,可以这样给类的成员变量赋初始值
    };
    

    那么没有办法使用ex2 tmp;这种方法,在不提供实参的前提下初始化对象,而只能够ex2 tmp(1, 0.0);来初始化。但是如果还是想要用原来不提供实参的方法初始化那怎么办呢?

    class ex2{
    public:
        ex2() = default;
        ex2(int e, float f):b(e), c(f) { };
    private:
        int a;
        int b;
        float c = 0.0;    // 顺带一提,可以这样给类的成员变量赋初始值
    };
    

    使用default关键字(注意,这是C++11的标准)就可以指定该构造函数为默认构造函数,不接受任何实参。这个构造函数可以完全等同于之前我们提到的合成默认构造函数(即什么都不写的时候编译器自动加上的默认构造函数)。此外值得一提的是上面的ex2(int e, float f):b(e), c(f) { };中使用了初始值列表来初始化参数,这种方法其实和在函数体中,即{b = e;}没什么区别,只是效率更高,而且当成员变量是const的时候只能够通过初始值列表来给成员变量一个值(因为通过初始值列表来指定值的操作是初始化成员变量的值,而不是赋值const其实做的就是禁止赋值操作)。

    参考

    C++ 类的定义与实现
    C++ 类 & 对象
    C++类的介绍
    《C++ Primer》

  • 相关阅读:
    【转】微信中MMAlert(半透明底部弹出菜单)的使用介绍
    工厂模式
    装饰者模式
    观察者模式
    策略模式
    Android 自定义ViewGroup,实现侧方位滑动菜单
    【转】Android Android属性动画深入分析
    Android ActionBar仿微信界面
    书籍:《沧浪之水》、《盜墓筆記1-8全集》、《鬼 吹 灯(1-8加续)》、《流浪地球》、《二号首长1-5》
    FROM_UNIXTIME 格式化MYSQL时间戳函数
  • 原文地址:https://www.cnblogs.com/yejianying/p/cpp_notes_class.html
Copyright © 2020-2023  润新知