【C++】Essential c++ 第四章学习笔记
发布日期:2021-05-08 14:57:17 浏览次数:14 分类:精选文章

本文共 6194 字,大约阅读时间需要 20 分钟。

Essential C++ 第四章

1. 类的组成

通常一个类的基本组成元素包括成员变量和成员函数。按照权限进行分类的话,可以分为private和public两种。public的成员,意味着可以通过任何方式访问这些成员;private意味着,只有在类中才能访问这些成员。

例如:

class myClass {    public:        int _b;        void print() {            cout << _a << endl;        }    private:        int _a;};

在上面的类中,_b是public的,所以myClass的实例cls可以通过类访问符进行直接访问;而_a是private的,不能通过实例cls进行直接访问,因为private的对象只能由类的成员进行访问,比如其成员函数print可以访问。

值得注意的一点是,如果定义类成员的时候,前面不写public和private,编译器会默认这些成员是private的。

2. 类的构造

构造函数和析构函数是一类特殊的成员函数。构造函数是类进行定义的时候进行调用的,用来初始化类中的变量;析构函数在类使用完毕后进行调用,用于清空构造这个类时所申请的全部内存空间。

构造函数和析构函数都是没有返回值的函数,并且与类是同名的。

例如:

class myClass {    public:        myClass(int a) {            _a = a;        }    private:        int _a;};

如果你没有定义构造函数和析构函数,编译器有默认的构造函数和析构函数,他们没有任何输入参数。

2.1 构造函数

构造函数主要是用来给类赋予初值的,有函数体内赋值和初始化列表赋值两种,同时也可以像非类成员函数那样具有默认值。

  • 函数体内赋值:
class myClass {    public:        myClass(int a) {            _a = a;        }    private:        int _a;};
  • 初始化列表:
class myClass {    public:        myClass(int a, int b) : _a(a), _b(b) {        }    private:        int _a;        int _b;};
  • 带有默认值的构造函数:
class myClass {    public:        myClass(int a = 1, int b = 1) : _a(a), _b(b) {        }    private:        int _a;        int _b;};

2.2 析构函数

析构函数前面具有一个~,也没有返回值。

例如:

~myClass() {}

2.3 拷贝构造

在进行类创建的时候,往往会需要以原有的实例创建新的实例对象。例如:

class myClass {    public:        myClass(int a) : _a(a) {        }    private:        int _a;};myClass a(1);myClass b = a; // 拷贝构造

在第一章的内容中,我们知道以下两种对变量的定义方法是等效的:

int a = 1;int a(1);

对类的拷贝来说,也是一样的。myClass b = a和myClass b(a)是等价的。myClass b(a)这种写法与构造函数非常相似,但是我们定义的构造函数并不接受myClass这种类型的参数输入,那么对象b到底是怎么被构造的呢?

原来,C++中,有种默认的拷贝构造函数,能够接受同类对象。因此,实际上b(a)这种写法,调用的不是构造函数,而是默认拷贝构造函数,默认拷贝构造函数会在下一个小节进行讲述。

2.4 拷贝构造(继续)

默认拷贝构造函数会进行一一复制操作。如果一个数据变量是一个指针类型的话,拷贝构造之后,会使得两个变量指向同一个地址。如果你的类中,涉及到地址的话,复制的时候就要格外小心了,以防内存访问错误问题。

例如:

class myClass {    public:        myClass() {            int *p = new int[3];        }    private:        int *p;};int main() {    myClass a;    myClass b(a);}

这种情况下使用默认的拷贝构造函数就是一种非常危险的情况,因为new定义的变量是单独的,必须通过delete才能够使电脑释放这部分内存,而经过默认的拷贝构造后,a和b的变量p指向了同一块内存,第一个析构函数调用时,会清空这个内存。第二个析构函数调用时,又会来清空这块内存,但是这块内存以及刚刚被清除了,于是就会发生内存访问错误,为了避免这种情况的发生,必须要使用自定义的拷贝构造函数。

2.5 自定义拷贝构造函数

自定义拷贝构造函数,就是定义一个输入类型为自身的构造函数。

例如:

class myClass {    public:        myClass() {            int *p = new int[3];        }        myClass(myClass m) {            int *p = new int[3];            for (int i = 0; i < 3; i++) {                this->p[i] = m.p[i];            }        }    private:        int *p;};int main() {    myClass a;    myClass b(a);}

3. 类成员的管理

3.1 通过const和mutable进行类修改权限管理

  • const:当你定义一个成员函数时,如果这个成员函数并没有改变对象内的任何一个数据时,就可以把它设置为const,const意味着这个类不能对对象作出修改。

例如:

#include 
using namespace std;class myClass { public: myClass(int a) : _a(a) { } void print() const { cout << _a << endl; } void a_plus() { _a++; } private: int _a;};int main() { myClass cls(1); cls.print(); cls.a_plus();}
  • mutable:是针对变量来说的,可以让const函数修改类中的mutable变量。

例如:

#include 
using namespace std;class myClass { public: myClass(int a) : _a(a) { } void print() const { cout << _a << endl; } void a_plus() const { _a++; } private: mutable int _a;};void f(const myClass &cls) { cls.a_plus(); cls.print();}int main() { myClass cls(1); f(cls);}

3.2 通过静态进行内存管理

  • 静态变量的特性

    • 隐藏性:在这个cpp文件里面定义的变量,其他cpp文件不能调用。
    • 永久性:静态变量在main函数运行之前被定义好,只能发生一次初始化,并且全局有效。
  • 静态的成员变量

    • 类的所有对象都能够使用这个变量,并且这个变量值是固定的。
    • 初始化通常在类外面进行。

例如:

#include 
using namespace std;class A { public: static int i; static void f() { cout << i << endl; } private: static int i;};int A::i;int main() { A a; a.i = 10; A b; cout << b.i << endl; cout << A::i << endl; A::f(); return 0;}
  • 静态的成员函数:只能通过类名进行访问,内部不能使用this指针。

3.3 通过友元进行访问权限管理

友元可以为某个函数或类赋予访问私有成员的权限。

例如:

#include 
using namespace std;class myClass { public: friend class ClassB; friend void f(myClass A); private: int _a;};class ClassB { public: void f(myClass A) { cout << A._a << endl; }};void f(myClass A) { cout << A._a << endl;}int main() { myClass A(1); ClassB b; b.f(A); f(A);}

3.4 this指针

this指针指代的就是类定义的实例其本身,可以用来返回类自己。

4. 运算符重载

运算符重载本质就是一种特殊的成员函数,允许自定义类进行特定的运算。

4.1 运算符重载的规则

  • 不能改变运算符的变量个数。
  • 不能创造新的运算符。
  • 运算符的变量中,必须出现类。
  • 运算符的优先级不能改变。

4.2 双目运算符的重载

  • 在类外重载运算符:
int operator+(myClass &A, myClass &B) {    return A._a + B._a;}
  • 在类内重载运算符:
class myClass {    public:        myClass(int a) : _a(a) {        }        int _a;        int operator+(myClass &B) {            return _a + B._a;        }};

4.3 单目运算符的重载

  • 运算符++:
class myClass {    public:        myClass &operator++() {        }        myClass operator++(int) {        }};

4.4 提领运算符的重载

int operator*() const {}

4.5 函数调用符的重载(函数对象)

函数对象用于STL算法中的函数调用。

4.6 赋值符的重载

class Matrix {    public:        Matrix &operator=(const Matrix &mat) {            if (this != &mat) {                this->_row = mat->_row;                this->_col = mat->_col;                delete[] _pmat;                _pmat = new double[elem_cnt];                for (int i = 0; i < elem_cnt; i++) {                    _pmat[i] = mat._pmat[i];                }            }            return *this;        }    private:        int _row;        int _col;        double *_pmat;        int elem_cnt;};

4.7 iostream的重载

  • 定义在类外:
class myClass {    public:        int length;};ostream &operator<<(ostream &os, myClass &rhs) {    os << rhs.length << endl;    return os;}
  • 使用方法:
myClass cls;cout << cls << endl;
  • 另一种定义在类外的方法:
class myClass {    public:        int length;};ostream &operator<<(myClass &rhs, ostream &os) {    os << rhs.length << endl;    return os;}
  • 定义在类内:
class myClass {    public:        ostream &operator<<(ostream &os) {            os << length << endl;            return os;        }    int length;};

5. 指针—指向类成员函数的指针

指向类成员的指针和指向普通函数的指针比较相似。例如:

class myClass {    public:        void f() {            cout << "1" << endl;        }    typedef void (myClass::* ptr)();    private:};typedef myClass::ptr ptr;int main() {    myClass cls;    ptr p = &myClass::f;    (cls.*p)();    return 0;}
上一篇:【C++】Essential c++第五章学习笔记
下一篇:【C++】Essential c++ 第三章学习笔记

发表评论

最新留言

做的很好,不错不错
[***.243.131.199]2025年03月26日 21时56分04秒