本章节最主要讲了在类的构造和析构方面, 内存是怎样分配的, 还有几个关键字 : static, const, virtual, inline, 各种重载等等知识点.
1. 究竟什么时候需要自己写构造函数, 赋值函数, 拷贝构造函数?
只要你写的这个类, 在类里面会动态分配内存(就是new一个类型出来), 你就要自己写一份 构造函数, 赋值函数, 拷贝构造函数. 这是为啥呢? 下面来看例子
class a{a(int a_v):value(a_v){}~a();
private:int value;
}//a.h
class A{
public:A(int height, int width);~A();
private:int gao;int kuan;a **m_cell;
}//A.h
//创建一个N*N的矩阵
A::A(int height, int width){m_cell = new a* [height];for(int i=0;i
我们可以看到, 书上用new的方法创建了一个二维数组(矩阵), 那么理所当然, 有new就会有delete, 所以我们在析构函数里面, 也要对分配的内存进行释放.
A::~A(){for(int i=0;i
OK处理完构造函数和析构函数后, 我们再来研究 赋值函数 和 拷贝构造函数
还记得什么时候调用 赋值和拷贝构造函数嘛?
当一个对象不存在时, 就调用拷贝构造函数
当一个函数存在时, 调用赋值构造函数
OK我们来看以下两种情况:
A(3,4);
printA(A);
首先我们先理解一个东西!很重要!
浅复制: 如果没有写自己的拷贝构造函数和赋值构造函数, 就会调用默认的函数去执行, 当遇到一个基础类型需要用到这两个函数时, 编译器通常会采取浅复制的方法去实现, 具体就是从源对象直接复制给目标对象, 直接复制!!!
当我们构造一个A的时候, 由m_cell指针 指向每个矩阵的元素, 假设我存在一个函数printA(), 接收一个对象并且打印其矩阵时, 这个printA()函数是创建一个和m_cell指向同一个地址的指针, 相当于创建一个副本, 所以我们对这个副本进行修改时, 也会修改m_cell指向的值 , 更糟糕的是!!! 当这个printA()函数结束的时候, 会调用A 的析构函数, 导致释放了副本指向的内存, 导致了m_cell 指向了一个未知区域.
A a(3,4),b(5,6);
b=a;
这个有什么问题呢? 当我们构造完a和b 的时候, 他们各自的m_cell 指针指向了不同的两个内存, 当我们执行 b=a 的时候, 就会看到b.m_cell 指向了 a.m_cell所指向的地址.导致了b.m_cell指向了一个未知区域.
所以对于存在动态分配内存的类, 应该编写自己的赋值函数和拷贝构造函数, 这样才能安全的使用这个类.
具体做法就是. 先get到源参数的每一个值, 然后自己赋值,拷贝构造函数自己再new动态内存去 保存get得到的值.
2.static
静态成员:
我是这么理解这个static: 就是这个static 修饰了某一个成员后, 这个成员就是对于类来说 而不是 对于类的对象来说. 怎么理解呢?
class a{
public:static int abc();
private:static int b;
}//a.hint a::b=0;
static int a::abc(){b++;}
//a.cpp
这个时候, 我们这么理解b, b就是这个a类之间的一个共享数据. 就相当于a类的”全局变量”, 这个做法就像声明一个全局变量一样, 不过作用范围是a类们之间.
static静态成员变量不能在类的内部初始化。在类的内部只是声明,定义必须在类定义体的外部,通常在类的实现文件中初始化
静态方法:
我是这么理解这个static: 和前面静态成员一样, 当一个函数我们要其的作用于类而不是类的对象时, 就是这个静态方法 服务于a类们之间, 我们就把这个abc方法设置成静态 .
注意:
1. 静态方法因为作用于整个类, 而不是类的对象, 所以不存在this指针, 因为没有对象存在了嘛.
2. 静态方法只能访问类的protected和private的静态成员!!! 就是不可以在静态方法里面调用非静态成员!!!
3.const
class a{
public:~a();a(int aa):b(aa){}void abc() const;
private:const int b;static const int bb;
}
const成员:
const的东西 就是表明了 创建了之后就不可以改动了!!!
一旦改动就会报错, const成员变量也不能在类定义处初始化,只能通过构造函数初始化列表进行,并且必须有构造函数。
const数据成员 只在某个对象生存期内是常量,而对于整个类而言却是可变的。因为类可以创建多个对象,不同的对象其const数据成员的值可以不同。所以不能在类的声明中初始化const数据成员,因为类的对象没被创建时,编译器不知道const数据成员的值是什么。
const数据成员的初始化只能在类的构造函数的初始化列表中进行。因为const值需要在定义的时候立刻初始化 不能有先后顺序,(和引用一样)要想建立在整个类中都恒定的常量,应该用类中的枚举常量来实现,或者statc cosnt.
const成员函数: 在函数后面加一个const关键字目的就是为了不让这个函数去修改任何值, 当我们创建一个const 对象, 这个对象只可以调用const 方法(如abc),当我们创建一个非const对象, 可以调用const函数或者非const函数. 当然也有例外就是当我们真的很想在const函数里面修改某一个成员的值, 我们就这个值的声明前 添加 mutable 关键字.
static const 成员初始化.. 这个要研究一下才行. mark一下!!!
4.使用接口类和实现类
基本原则: 定义两个类: 一个接口类, 一个实现类, 接口类提供了实现类所提供的公共方法, 但它只有一个数据成员, 即指向一个实现类对象的指针. 接口类方法实现只是调用实现类对象上的应用方法. 123