您的位置:首页 > 编程语言 > C语言/C++

C++高级编程 第八章: 掌握类和对象

2017-10-30 18:53 225 查看
本章主要介绍类的基本构造和基本使用.包括 构造函数, 拷贝构造函数, 赋值构造函数

1. 类的基本构造

类基本包括构造函数和一个析构函数, 这个是最简单的类


class Number{

public:
Number();
~Number();

protect:
int num;
};


怎么访问成员就不细说了, 还有怎么编写该类的方法, 也不细说了,网上很多教程.

2.this指针

int Number::Count(int a){
this.num+=a;
}


每个常规的方法调用都会传递调用该方法的对象的一个指针, 将其作为隐藏的第一个参数.在函数体里面, 可以直接调用this来获取调用该方法的对象.

3.了解堆和栈

我们平时在创建对象或者创建内置类型时, 可以有两种方式创建. 一种时堆上创建, 另外一种时栈上创建.

首先理解程序的内存分配:

一个由C/C++编译的程序占用的内存分为以下几个部分

栈区(stack)— 由编译器自动分配释放 ,存放函数的参数值,局部变量的值等。其操作方式类似于数据结构中的栈。

堆区(heap) — 一般由程序员分配释放, 若程序员不释放,程序结束时可能由OS回收.注意它与数据结构中的堆是两回事,分配方式倒是类似于链表.

全局区(静态区)(static)—,全局变量和静态变量的存储是放在一块的,初始化的全局变量和静态变量在一块区域, 未初始化的全局变量和未初始化的静态变量在相邻的另一块区域.程序结束后由系统释放

Number A
A.Count(1);

Number B = new Number;
B->Count(1);


A对象是栈上的对象, 我们创建一个对象像声明简单变量一样, 就像 int a = 1 ; 所以采用”.”操作符

B对象是堆上的对象, 我们创建一个对象使用到new方法. 用New动态分配内存给B. 所以采用”->”操作符, “->”包含了两个作用 一个是”*” 解引用, 一个是”.” 完成成员或者方法访问.

4. 构造函数

定义: 构造函数我的理解就是: 一个类 它的对象生成时, 就需要构造函数帮它实现这个生成的过程

具体有两种构造形式, 成员初始化列表和构造函数体. 下面就来说说两者的区别.

class Number{
public:
Number(int a):num(a){}
~Number();
private:
int num;
}//这个是成员初始化列表


class Number{
public:
Number(int a){num = a;};
~Number();
private:
int num;
}//这个是函数体构造


两者的差别:

函数体构造: 是先定义变量, 再给变量赋值.

初始化列表: 在定义的时候直接给变量赋值, 两者没有先后的顺序

因为先后顺序的问题,所以在以下情况必须使用初始化列表:

初始化一个引用的成员变量

初始化一个const变量

当我们在初始化一个子类对象的时候,而这个子类对象的父类有一个显示的带有参数的构造函数

当调用一个类类型成员的构造函数,而它拥有一组参数的时候

初始化一个引用的成员变量: 当一个引用的成员变量产生时, 需要立刻对变量进行赋值, 就是定义和赋值 要同时进行, 不能有先后顺序.

初始化一个Const变量: Const变量也是 要定义的时候就要赋值, 不可以有先后顺序.

因为子类对象包括父类对象,父类对象既然明确指定了带参的构造函数,那么就必须在构造子类对象的父类部分时显示调用这个构造函数,是不能依赖于合成的默认构造函数的,而这样的话,就必须在成员初始化列表中调用

类型的成员所在类如果有”显示定义的构造函数”那么也是需要在定义这个成员的同时需要显示调用的。

性能的差别

class Number{
public:
Number(){con=0,num=0};
~Number();
private:
string con;
int num;
}


函数体构造流程:

1.执行string的构造函数

2. 定义一个temp变量接收”0”

3. 调用赋值操作符函数去改变con

4. 调用string析构函数

5. 将num设置为0

初始化列表流程

1.直接get到con变量并且set为0

2.直接将num变量set为0

所以综合来看: 初始化成员列表更加方便构造函数的实现 和 更加效率. 所以建议使用初始化列表来写构造函数

tips: 数据成员会按其出现再类定义中的顺序去初始化, 而不是按照初始化列表的顺序.

5. 拷贝构造函数

class Number{
public:
Number();
Number(const Number& temp) :num(temp.num){}//拷贝构造函数

~Number();
private:
int num;b

}


拷贝构造函数为什么要const 和 取引用: 因为const能够避免再拷贝的过程中对temp对象修改, 而采取引用不采取传值: 因为传值要对 值进行复制 , 而引用不需要, 只需要取其地址, 能够提高效率.

书中定义: 拷贝构造函数是C++独有的,它是一种特殊的构造函数,用基于同一类的一个对象构造和初始化另一个对象。允许创建一个对象作为另一个对象的完全副本. 对于拷贝构造函数里面的数据成员 会采取 他们对应的拷贝构造函数.


6.赋值函数

class Number{
public:
Number();
Number(const Number& temp) :num(temp.num){}//拷贝构造函数
Number& operator=(const Number& rhs);//赋值函数
~Number();
private:
int numb

}


书中定义: “拷贝”只会出现再对象初始化时才会出现, 如果一个对象已经存在或者已经 有值, 那么如果想重写或者覆盖这个对象, 就需要一个赋值函数来指引.

其实可以理解 A=B; A就是一个已经存在的对象, 而B 就是我们想get到的对象, 所以我们要定义这个”=”, 这个”=” 里面 就是怎样将懒对象赋值 给 另一个对象. 调用这个”=”就是lhs, 而源对象就是右边, 称为”rhs”.

然后我们看函数结构 : 它返回的是一个对象的引用, 这里有两个问题, 第一个就是为什么返回对象的引用, 第二个就是 既然是引用,那么修改A的话B也会修改吗?

第一个问题: 如果不把引用作为返回值, 而是直接返回对象的话, 在函数结束时, 会生成一个temp的对象, 用来存储返回的对象, 然后再把这个temp对象赋值给A,所以中间存在两次赋值, 而采取引用的方式可以 减少这种降低效率的行为.

第二个问题: 测试完再补充.

7.区分何时用拷贝构造函数和赋值函数

拷贝构造函数是一个对象初始化一块内存区域,这块内存就是新对象的内存区,而赋值函数是对于一个已经被初始化的对象来进行赋值操作。

就是这么理解:

A a;

A b(a);//b 是不存在的!!它只是一个新的内存对象区 , 调用拷贝构造函数

A c=a;//c 是不存在的!!它只是一个新的内存对象区 , 调用拷贝构造函数

A d;

d=a; //d 是存在的, 调用赋值函数

**

总结情况: 看别人的博客总结的!!!

**

当一个对象不存在时, 用别的对象来进行初始化, 就调用拷贝构造函数.

例如:

当对象作为函数参数进行值传递的时候. 就相当于 A c=a;

当对象作为函数返回值进行值的返回的时候. 就相当于 A c=a;

当一个对象需要另外一个对象进行初始化的时候, 相当于 A c=a; A b(a);

当一个对象已经存在, 用别的对象进行初始化的时候, 就用赋值函数.
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: