C++进阶笔记
思想原则:
以类为例,类最终要处理的是数据,方法只是过程,最终要改变的是private中的数据成员状态。程序设计也是如此,要的是数据。
一、const的作用
const定义变量:定义了一个不可修改的常量;
const用于返回值:通常是用于限定指针和引用,用于防止返回值处于左值时被修改;
const用于参数:防止原数据被修改;
const用于函数名后:防止类成员函数调用时被修改;
二、引用、指针、值传递
引用除了在函数头的参数中添加了&符号,其他行为和值传递是一样的;
引用是一种别名的行为,使用的是原始数据,因此不需要像值传递一样使用匿名变量的额外开销;
指针相对引用比较麻烦,指针需要开辟存储空间用于存储变量的地址,而且使用时需要解除引用,相对引用来说比较麻烦,因此在值传递的过程中,使用引用传递相对来说轻松些。
何时使用值传递
·当数据对象较小,如内置基本类型和小型结构体,且不需要修改原数据时
何时使用指针
·当数据对象是数组,则使用指针,这是唯一的选择
·当数据是基本类型且需要修改原数据时
何时使用引用
·当数据对象是类对象时
何时使用指针或引用
·当数据对象是较大结构体时
三、递归函数
执行递归函数时,递归语句前的程序按照条件正序执行一遍,然后递归语句后的程序倒叙执行一遍。
四、作用域和链接性
首先对变量分类:自动变量(局部变量)、静态变量(区别于new创建的动态变量)、动态变量(new创建的在运行时赋值的变量);
通常,编译器使用三块独立的内存:一块用于自动存储,一块用于静态存储(可能再细分),另一块用于动态存储。
变量类型 | 作用域 | 链接性 | 如何声明 |
---|---|---|---|
自动变量 | 代码块 | 无 | 在代码块中 |
静态,外部链接性变量 | 全局 | 文件之间 | 不在任何函数内 |
静态,内部链接性变量 | 此文件内 | 此文件内 | 不在任何函数内,使用static |
静态,无链接性变量 | 代码块 | 无 | 在代码块内,使用static |
const,内部链接性变量 | 此文件内 | 此文件内 | 不在任何函数内,使用const |
const,外部链接性变量 | 被引用文件内 | 被引用文件内 | 不在任何函数内,使用extern const |
const,无链接性变量 | 代码块 | 无 | 在代码块内,使用const |
注意:静态成员(static)只初始化一次,
另外,通常函数的链接性为外部性,但是可以使用static使其作用域变成此文件内。
五、构造函数
使用构造函数
常规赋值方法,例如整型和结构体:
//整型
int a=3;
//结构体
struct str={1,"code",1.23};
但这种方式不能给类的对象赋值,因此采用构造函数进行赋值;
构造函数用于给对象的数据成员
进行赋值,使用方法如下:
//显示调用
Stock food=Stock(1,"code",1.23);
//隐式调用
Stock food(1,"code",1.23);
默认构造函数
以下用法将调用默认构造函数:
Stock food;
就是只创建对象,但不初始化,则调用默认构造函数进行初始化。
有两种默认构造函数,
一种是给参数提供默认值:
Stock(int a=1,std::string str="code",double c=1.23)
另一种是通过函数重载:
Stock::Stock()
{
m_a=1;
m_str="code";
c=1.23;
}
六、析构函数
和构造函数相对应,构造函数在创建对象时主动调用构造函数进行给数据成员赋值,默认构造函数则会在特定情况下自动调用,析构函数则是在函数过期时自动调用的函数,本身的功能就是自动调用,并不附加额外功能,有些书本的定义实在令人产生歧义!
Stock::~Stock
{
//detele xxx;
std::cout<<"此函数终结!"<<std::endl;
}
七、this指针
有时对象调用方法会修改对象的数据成员,这时需要返回新修改后的对象,就可以使用this指针进行返回;
每个对象都有一个this指针指向自己的地址。
八、对象数组
初始化对象数组使用列表初始化方式:
Stock food[3]={
Stock(1,"one",1.23),
Stock(2,"two",2.23),
Stock(3,"three,3.23")
} ;
八、作用域为类的常量
由于类只有在创建对象时才会分配空间,所以在类中无法使用 const int a=3;
这种形式,因为此时还未分配空间,有两种方法解决这个问题,
第一种方法是使用枚举,枚举不创建值,只是一种替换,例如下边是使用12替换了Month,有点像宏定义?
第二种方法是使用static,使用static会创建一个常量,此时该常量是存储在静态存储区,而不是在类对象中。
class stock
{
private:
//第一种是在类中声明一个枚举
enum{Month=12};
//第二种是使用static
static const int Day=31;
}
九、友元函数
友元函数是非成员函数,不能被对象调用,但是友元函数的访问权限和成员函数一样,可以访问私有数据成员。
一般将运算符重载函数声明为友元函数,因为这样就可以显示调用参数。
十、隐式转换
1.只有接受一个参数的构造函数才能作为转换函数,使用explicit可关闭隐式转换。
十一、复制构造函数
复制构造函数用于将一个对象复制到新创建的对象中,即新建一个对象并将其初始化为同类现有对象时,复制构造函数将被调用。
当程序生成对象副本时,编译器都将使用复制构造函数,具体地说,当函数按值传递对象或函数返回对象时,都将使用复制构造函数,或者在进行三个对象相加时,编译器也可能生成临时对象储存中间值并调用复制构造函数。
默认复制构造函数的功能
默认复制构造函数逐个复制非静态成员(成员复制也成为浅复制),复制的是成员的值。
如果类成员中使用了new初始化的指针成员,应当定义一个复制构造函数,以复制指向数据,而不是指针,这被成为深复制。
初始化对象时有两种可能:
第一种是不通过赋值运算符,而是通过复制构造函数创建对象;
第二种是通过复制构造函数创建临时对象,再将临时对象通过赋值运算符复制。
总之,初始化对象一定会调用复制构造函数,而默认复制构造函数和默认赋值运算符进行的都是浅复制,所以要显示定义复制构造函数和赋值运算符,将new生成的指针部分进行值复制而不是地址复制。
十二、运算符重载
只能通过成员函数重载的运算符:
=
()
[]
->
十三、new
new的作用是为指针分配内存;
在构造函数中使用new,就必须在析构函数˙中使用delete;
如果有多个构造函数,就必须以相同的方式使用new,因为只有一个析构函数。
十四、返回对象
通常使用const引用 返回对象效率更高,因为返回值会调用复制构造函数;
两种返回非const引用对象的情形是:重载运算符和重载cout<<,前者目的在于方便赋值,后者是必须这样做,以便连续输出。
什么情况下返回对象(不带引用)呢?就是在返回值为局部变量时需要使用返回对象。
返回const对象:不希望返回值被修改。好像一般较少使用。
十五、转换函数
将值转换为类,只需要定义一个只有一个参数的构造函数;
将类转换为值,需要定义类成员函数,operator type_name();
十六、派生类构造函数
构造函数使用初始化列表可减少一个步骤,速度更快。
派生类构造函数举例:
RatedPlayer::RatedPlayer(unsigned int r,const TableTennisPlayer& tp)
:TableTennisPlayer(tp),rating(r)
{
}
十七、虚函数(虚方法)
虚函数允许基类和派生类使用各自的方法,前提是使用指针或引用传递函数。
在派生类中,通常使用作用域运算符调用基类方法。
基类指针可以指向派生类对象,因此可以创建基类指针数组,用来将基类对象和派生类对象储存在一个数组中【499页】。
虚析构函数:
为什么需要虚析构函数?因为有了虚析构函数就可以调用基类和派生类各自实现的虚构函数了。
十八、访问控制
有三种访问控制方式:Public(公有)、Private(私有)、Protected(保护)。
Public:可以在类外使用作用域运算符调用;
Private:只能通过成员函数调用;
Protected:正常情况下和Private一样,只有在派生类中有区别,对于派生类来说,保护成员和公有成员一样,好像还不用通过作用域运算符而直接调用?
十九、抽象基类(ABC类)
抽象基类又称ABC类,指的是至少使用一个纯虚函数的接口。
二十、什么不能被继承?
构造函数
析构函数
赋值运算符=
友元
二十一、继承和包含
继承有:公有继承,私有继承和保护继承;
公有继承,除了二十提到的之外都能继承,包括接口(数据成员)和实现(方法);
私有继承,私有继承和包含具有同样的效果,基类的私有成员变成不可访问,基类的公有成员和保护成员变成私有成员,就是说只有派生类的成员函数才可以访问他们;
保护继承,派生类的公有成员和保护成员都将变成保护成员;
包含,包含继承实现但不继承接口。
--- --- ---
包含和私有继承的区别:
大多数情况下使用包含而不是私有继承来表示has-a的关系,
使用私有继承的两种情况,
- 访问基类的保护成员;
- 需要重新定义虚函数。
二十二、this指针
this指针指向调用该方法的对象,举个例子:
加入Student是类,Name()是类的方法,则:
const string& Student::Name() const
{
return (const string&) *this;
}
其中,this代表Student。
二十三、使用using重新定义访问权限
说明,派生类内指的是类的定义内,派生类外指的是对象调用,同时,该方法只适用于继承不适用于包含。
假设派生类没有特别书写一个调用基类的方法,则可以使用using重定义基类的访问权限。例如:
class Student: private std::string,private std::valarray<double>
{
...
public:
using std::valarray<double>::min;
using std::valarray<double>::max;
...
};
则可以这样使用:
std::cout<<"the max is:"<<ada[i].max()<<std::endl;
二十四、关于继承和初始化列表
继承和初始化列表都使用冒号:
在class后的是继承,在构造函数后的是初始化列表。
```c
//继承
class Abc():public std::string
{
private:
int aaa;
};
//初始化列表
Abc::Abc():aaa(5)
{}
```
二十五、类模版
模版不是类,模版成员函数也不是成员函数,因为他们不参加编译,只有实例化后才参与编译。因此通常将模版声明和模版定义放在同一个.h文件,使用的时候调用头文件即可。
模版是重载的一种形式,只有类型需要替换而其内部代码不变。
模版累可用作基类,也可用作组件类,还可以用作参数。
模版可以使用多个参数,可以是抽象参数,也可以是具体参数。
模版可以作为类的成员。
二十六、友元
友元类
不只是函数可以作为友元(友元函数),类也可以作为友元(友元类),举个栗子:
电视机TV和遥控器Remote,
电视机和遥控器是两个独立的类,
但是遥控器可以改变电视机的状态,如换台,调音等,
因此遥控器是电视机的一个友元类,
友元声明可以位于公有,私有或者保护部分,
友元类也是单独的类,但是具有访问原类数据的权限,就是说两个类共享一组数据。
//.h文件
class TV
{
public:
friend class Remote;
......
};
class Remote
{
private:
int mode;
......
};
//.c
int main()
{
Remote grey;
grey.volup(50);
}
如果只让Remote类的一个方法成为友元成员,需要使用前向声明小心排列声明顺序(P606)
二十七、嵌套类
嵌套类的问题在于初始化。
解决方法是在调用嵌套类的方法中初始化嵌套类。
class Queue
{
class Node
{
public:
Item item;
Node* next;
Node(cosnt Item& i):item(i),next(0){}
};
......
bool Queue enqueue(const Item& item)
{
//简洁初始化方式
Node* add=new Node(item);
......
//另一种初始化方式
Node* add=new Node;
add->item=item;
add->next=NULL;
}
...
};
C++进阶笔记的更多相关文章
- Angularjs进阶笔记(2)-自定义指令中的数据绑定
有关自定义指令的scope参数,网上很多文章都在讲这3种绑定方式实现的效果是什么,但几乎没有人讲到底怎么使用,本篇希望聊聊到底怎么用这个话题. 一. 自定义指令 自定义指令,是Angularjs用来实 ...
- javascript进阶笔记(2)
js是一门函数式语言,因为js的强大威力依赖于是否将其作为函数式语言进行使用.在js中,我们通常要大量使用函数式编程风格.函数式编程专注于:少而精.通常无副作用.将函数作为程序代码的基础构件块. 在函 ...
- Android进阶笔记:Messenger源码详解
Messenger可以理解为一个是用于发送消息的一个类用法也很多,这里主要分析一下再跨进程的情况下Messenger的实现流程与源码分析.相信结合前面两篇关于aidl解析文章能够更好的对aidl有一个 ...
- Android进阶笔记:AIDL内部实现详解 (二)
接着上一篇分析的aidl的流程解析.知道了aidl主要就是利用Ibinder来实现跨进程通信的.既然是通过对Binder各种方法的封装,那也可以不使用aidl自己通过Binder来实现跨进程通讯.那么 ...
- javascript进阶笔记(1)
学习js已经有一段时间了,大大小小还是能够做出一些东西来.不过觉得可惜的是,还是对js本身这门语言不是很熟悉,总有一点雾里看花的感觉,看得见,但是看不清楚.最近发现有一本关于js的叫做<忍者秘籍 ...
- object - c 语言基础 进阶笔记 随笔笔记
重点知识Engadget(瘾科技)StackOverFlow(栈溢出)Code4Apprespon魏先宇的程序人生第一周快捷键: Alt+上方向键 跳到最上面 Alt+下方向键 跳到最下面 ...
- python进阶笔记 thread 和 threading模块学习
Python通过两个标准库thread和threading提供对线程的支持.thread提供了低级别的.原始的线程以及一个简单的锁.threading基于Java的线程模型设计.锁(Lock)和条件变 ...
- Android进阶笔记20:Android手机屏幕坐标系
1. 手机屏幕坐标系: 整个坐标系是以手机屏幕左上角为原点(0,0),如下:
- Android进阶笔记19:onInterceptTouchEvent、onTouchEvent与onTouch
1.onTouch方法:onTouch方法是View的 OnTouchListener借口中定义的方法,处理View及其子类被touch是的事件处理.当一个View绑定了OnTouchLister后, ...
- Android进阶笔记18:选用合适的IPC方式
1. 相信大家都知道Android进程间通信方式很多,比如AIDL.Messenger等等,接下来我就总结一下这些IPC方式优缺点. 2. IPC方式的优缺点和适用场景 3. 附加:使用Intent实 ...
随机推荐
- [BZOJ 1146] [CTSC2008]网络管理Network(树状数组+主席树)
题目描述 M公司是一个非常庞大的跨国公司,在许多国家都设有它的下属分支机构或部门.为了让分布在世界各地的N个部门之间协同工作,公司搭建了一个连接整个公司的通信网络.该网络的结构由N个路由器和N-1条高 ...
- hdu 6141 I am your Father!
题 OvO http://acm.hdu.edu.cn/showproblem.php?pid=6141 (2017 Multi-University Training Contest - Team ...
- playbook 实例
vim ~/.vimrc autocmd FileType yaml setlocal sw=2 ts=2 et ai 变量使用及错误处理 --- - hosts: db remote_user: r ...
- 路由器配置——OSPF协议(2)
一.实验目的:使用OSPF协议达到全网互通的效果 二.拓扑图 三.具体步骤配置 (1)R1路由器配置 Router>enableRouter#configure terminalEnter co ...
- 【CUDA 基础】5.1 CUDA共享内存概述
title: [CUDA 基础]5.1 CUDA共享内存概述 categories: - CUDA - Freshman tags: - CUDA共享内存模型 - CUDA共享内存分配 - CUDA共 ...
- JavaWeb_(SSH)三大框架整合struts+hibernate+spring_Demo
三大框架整合 一.SSH导包 二.书写Spring 三.书写Struts 四.整合Spring与Struts 五.书写(与整合)Hibernate.引入c3p0连接池并使用hibernate模板 六. ...
- 如何在linux中发送邮件,使用163邮箱发信。
linux中,可以使用mail命令往外发送邮件,在使用前,只需要指定如下简单配置即可,这里演示用 163.com 邮箱发送至 qq.com 编辑 /etc/mail.rc,写入下方的参数 se ...
- CSS3 新特性
~平时喜欢逛博客,看别人的学习总结和遇到的问题解决办法,恰好最近在做书签整理,翻到了之前一个前辈移动前端的总结,所以我就按他的总结模块对自己的知识进行了梳理,不过由于都是手写的,为了方便,下面的都是平 ...
- GitHub代码下载和同步
1.下载git客户端https://git-scm.com/ssh-keygen -C "your@email.address" -t rsa 2. 把下面文件的内容复制到 htt ...
- 将ejs模板文件的后缀换成html
1.app.js的头部定义ejs: var ejs = require('ejs'): 2注册html模板引擎: app.engine('html',ejs.__express); 3.将模板引擎换成 ...