C++学习笔记

1、inline 关键字

  • 使用内联函数可以节省运行时间,因为编译的时候,内联函数相当于直接把代码copy到调用处,可以节省函数调用的堆栈开销。
  • 一般只将规模很小,使用频繁的函数生命为内联函数,从代码整洁角度来说,这是很合理的(但是真正的原因是?)。
  • 内联函数不能包含复杂的控制语句。
  • 类的成员函数也可以指定为内联函数。

2、 通过引用变量访问对象中的成员

  • 引用变量相当于为一个变量起别名,有时候他的功效和指针很像,底层是怎么实现的有待探讨。

3、构造函数的规则

  • 构造函数不需要用户调用,而是在建立对象时候自动调用(注意,这个在对象没有初始值的时候,是不会调用的,这个说话有误。)
  • 构造函数的名字必须和类名字相同,而不能有用户任意命名
  • 构造函数不具有任何类型,不返回任何值
  • 构造函数的功能有用户定义的,用户根据初始化的要求设计函数体和函数参数
  • 带默认参数的构造函数,会和默认构造函数产生歧义,比如 student(); 和 student(int age = 0); 会导致编译错误。 正确的写法为
    正确的写法:
    student();
    student(int);   // 不带默认参数

4、关于释构函数的注意点

  • 释构函数不返回任何值,没有函数类型,也没有函数参数
  • 释构函数不能被重载,一个类可以有多个构造函数,但是只能有一个释构函数
  • 释构函数的作用并不仅限于释放资源,它还可以被用来执行”用户希望在最后一次使用对象之后所执行的任何操作“
  • 如果用户没有定义释构函数,C++编译系统会自动生成一个释构函数

5、const关键字的作用

常对象

  • 用const修饰的对象,里面的所有成员变量不能被修改

  • 凡是希望数据成员不被修改的对象,都可以声明为常对象,声明方法: const object(0) 或者 object const(0);

  • 常对象成员变量必须有初始值,否则编译报错。

指向对象的常指针

  • 将指针变量声明为const类型,其指针的值不能改变

  • 一般定义方式为 object * const abc;

  • object a(0) , b(0) ; object * const pt = &a; pt = &b; //错误

指向常变量的指针变量

  • const object * a / object const * a;

  • 如果一个变量已被声明为常变量/对象,只能用指向常变量/对象的指针指向它,而不能用指向非

  • 指向常变量的指针变量可以指向未被声明为const的变量,但不能通过此指针变量改变该变量的值。

  • 指向常对象的指针最常用于函数的形参,以保护形参指针所指向的对象在函数执行过程中不被修改。

void doSomething1(const Test *p1)
{
p1->setX(5); //非法!
p1->printxy( );
}

| 数据成员 | 非const成员函数 | const 成员函数 |
| --- | --- || --- |
| 非const数据成员 | 可引用,可改变值 | 可引用,不可改变值
| const数据成员 | 可引用,不可改变值 | 可引用,不可改变值
| const对象数据成员 | 不可引用,不可改变值 | 不可引用,不可改变值

6、对象的赋值和复制

  • 同类对象之前可以互相赋值
  • 对象赋值的一般形式为 obj1 = obj2
  • 对象赋值的实现原理是赋值运算符的重载

7、对象的复制

  • 用已有的对象克隆出一个新对象
  • 其一般形式为 类名 对象2(对象1);
  • 原理是编译系统提供默认复制构造函数
  • C++的所有类型都实现了复制构造函数,基本类型也是,比如 int a(5),调用int的赋值构造函数,把参数5传入生成一个int 类型。
  • 当函数参数为类对象的时候,调用函数时,实参赋值给形参会调用对象的复制构造函来生成一个实参的拷贝
  • 当函数返回值为对象时,在函数调用完毕,会复制一个对象返回给调用处

复制构造函数:

Object::Object(const Object& b){
    a = b.a
}

8、友元

友元函数

  • 如果在本类以外其他地方定义的函数,在类体中用friend进行声明,此函数成为本类的友元函数,该函数可以访问类的私有成员变量。
  • 友元函数可以属于不是任何类的非成员函数,也可以是其他类的成员函数。
  • 一个函数(普通函数和成员函数)可以声明为多个类的友元函数,这样就可以访问多个类的私有数据。

友元类

  • 如何一个类中声明了其他类为友元类,那么其他类就可以随意反问这个类的私有数据。
  • 一般情况下不需要用到友元类,虽然友元类有助于数据共享,但是严重影响了类的封装性,不利于信息隐藏,大多数问题用友元函数就能解决。

9、运算符重载

运算符重载的意义

  • 通过运算符重载,扩大C++已有运算符的作用,使用运算符可以作用于类
  • 使用运算符重载技术,能使程序易于编写,阅读和维护
  • 运算符被重载后,其原有的功能依然保留,没有丧失或改变
  • 运算符重载实质是函数的重载

运算符重载的实现方法

对象+法运算符重载
成员函数实现 
// 写法一
object object::operator+(object & obj2){
    object obj3;
    obj3.a = obj2.a;
    return obj3;
}

// 写法二
object object::operator+(object & obj2){
    // 直接调用构造函数返回
    return object(obj2.a);
}


非成员函数实现方案
object operator+(object & obj1, object & obj2){
    // 直接调用构造函数返回
    return object(obj1.a + obj2.a);
}

运算符重载的规则

  • 不允许创造新的运算符,只能对已有C++的运算符进行重载
  • C++ 不允许的重载运算符有5个分别是:
成员运算符.
成员指针访问运算符.*
作用域运算符::
sizeof
条件运算符?:
  • 重载不能改变运算符运算对象(就是不能改变运算符的操作数)
  • 重载不能改变运算符的优先级
  • 重载不能改变运算符的结合性
  • 重载的运算符的函数不能带有默认参数
  • 重载的运算符必需和用户定义的自定义类型对象一起使用,参数至少有一个是类对象或其引用

10、类(继承类)访问权限

  • 访问权限不影响类的内存布局
  • struct 成员变量和继承方式默认都是public
  • class 成员变量和继承方式默认都是private
  • 如果成员变量和继承方式同时都有访问权限限制,则遵从最小访问权限原则,比如类继承是protected,但是成员变量是private,那么最终这个成员变量的权限还是private

| * |public | protected | private |
| --- | --- || --- | --- |
| 同一个类 | YES | YES | YES |
| 派生类 | YES | YES | NO |
| 外部类 | YES | NO | NO |

11、匿名函数——lambda表达式

  • 声明Lambda 表达式
[capture list] (params list) mutable exception -> return type { function body}
各项具体含义
1. capture list 捕获外部变量列表
2. params list 形参列表
3. mutable 指示符,用于说明是否可以修改捕获的变量
4. exception 异常设定
5. return type 返回类型
6. function body 函数体

// 实例
int a0 = 1;
int b0 = 2;
auto funcs = [=, &b0](int c)->int {return b0 += a0 + c;};
int ress = funcs(6);

12、命名空间

  • 为了解决C++标准库中的标识符与程序 中的全局标识符之间以及不同库中的 标识符之间的同名冲突,标准C++库的 所有的标识符都定义在一个名为std的 命名空间中。
  • C++有一个默认的命名空间,为全局命名空间为::
  • 命名空间是ANSI C++引入的可以由用户命名的作用域,用来处理程序中常见的同名冲突。
  • 同名字的命名空间会在编译过程中进行合并

13、有继承关系的构造函数调用

  • 子类会默认调用父类的无参构造函数
  • 如果子类的构造函数显示地调用了父类的有参构造函数,就不会再去调用默认构造函数
  • 如果父类缺少无参构造函数,子类的构造函数必须显示地调用父类的有参构造函数

14、多态

静态多态

  • 函数重载和运算符重载实现的多态性属于静态多态性
  • 在程序编译时系统就能决定调用的是哪个函数,因此,又称编译时的多态性
  • 静态多态性是通过函数的重载实现的(运算符重载实质上也是函数重载)

动态多态

动态多态性是在程序运行过程中才动态地确定操作所针对的对象,动态多态性又称运行时的多态性

  • C++默认没有实现动态多态,只会根据指针类型去调用对应的函数。
  • C++的动态多态通过virtual 函数来实现
  • 如果父类的函数是虚函数,子类重写该函数也是虚函数
  • 调用new object 和 new object() 是有区别的,后者会把成员变量初始化为0。

15、C++类型转换

  • 在C++中某些标准类型的数据之间可以自动转换
  • 隐式类型转换由C++编译系统自动完成的,用户不需要干预
int i  = 6;
i = 7.5 + i;
  • 强制(显式)类型转换是指在程序中将一中类型数据明确转换成另一指定的类型

const_cast

  • 一般用于去除const属性,将const转换成非const,比如
const Object obj1 = new Obejct();
Object * obj2 = static_cast<Object>(obj1);

const Person * pp1 = new Person();
//    pp1->age = 10; // error 因为是const 对象
Person * pp2 = const_cast<Person *>(pp1) ;
pp2->display();
pp2->age = 20;
pp2->display();

dynamic_cast

  • 一般用于多态类型的转换,有运行时安全检测。如果指针转换的时候,子类指针类型可以转换成父类,但是父类不能转换成子类。
class Person{
    virtual do();
};
class Student:public Person {
};
class Other{
};

Person * aa = new Person();
Person * bb = new Student();

Student * stu1 = dynamic_cast<Student*>(aa);// 返回为NULL
Student * stu2 = dynamic_cast<Student*>(bb);

Other * oth1 = dynamic_cast<Other*>(stu2); // 返回为NULL

//返回为NULL 证明类型转换失败

reinterpret_cast

  • 属于比较底层的强制转换,没有任何类型检查和格式转换,仅仅是简单的二进制数据拷贝
  • 可以交叉转换,可以将指针和整数互相转换

16、模板

  • C++中利用模板来实现泛型
  • 所谓的泛型,是一种将类型参数化以达到代码复用的技术
  • 模板的使用格式如下
template <typename\class T>
typename和class是等价的
  • 模板没有被使用时,是不会被实例化出来的
  • 模板的声明和实现如果分离到.h和.cpp中,会导致链接错误,所以一般将模板的声明和实现统一放到一个.hpp文件中

17、智能指针

传统的指针需要手动管理内存,非常容易导致内存泄露和野指针等问题,针对这一问题,C++采用了智能指针的方案来解决。

auto_ptr

  • auto_ptr 属于C++98标准,在C++11 已经不推荐使用(有缺陷,比如不能用于数组)
  • auto_ptr对象生命周期结束时,其析构函数会将auto_ptr对象拥有的动态内存自动释放
  • 一块动态内存只能被一个auto_ptr 对象持有。

shared_ptr

  • 被shared_ptr持有的对象会产生强引用,一个shared_ptr产生一个强引用计数
  • 可以通过shared_ptr的use_count 属性查看被引用对象的强引用计算器
  • 当有一个新的shared_ptr指向对象时,对象的强引用计数就会+1
  • 当有一个shared_ptr销毁时,对象的强引用计算就会-1
  • 当一个对象的强引用计算为0是(没有任何shared_ptr指向对象时),对象就会自动销毁(调用释构)
  • shared_ptr 会产生循环引用的问题,可以通过weak_ptr解决循环引用的问题

unique_ptr

  • unique_ptr也会对对象产生强引用,但是它可以确保同一时间只有一个指针指向对象
  • 当unique_ptr销毁时(作用域结束时),其指向的对象也就自动销毁
  • 可以使用std::move 函数转移unique_ptr的所有权
unique_ptr<Object>ptr1(new Object());
unique_ptr<Object>ptr2 = std::move(ptr1); //转移所有权 

make_shared

利用这个模板函数对智能指针进行初始化效率更好

//传统初始化智能指针的写法
std::shared_ptr<Widget> spw(new Widget);
//利用make_shared 函数初始化的写法
auto spw = std::make_shared<Widget>();
  • 每个std::shared_ptr都指向一个控制块,控制块包含被指向对象的引用计数以及其他东西。这个控制块的内存是在std::shared_ptr的构造函数中分配的。因此直接使用new,需要一块内存分配给Widget,还要一块内存分配给控制块。
  • std::make_shared申请一个单独的内存块来同时存放Widget对象和控制块。这个优化减少了程序的静态大小,因为代码只包含一次内存分配的调用,并且这会加快代码的执行速度,因为内存只分配了一次。另外,使用std::make_shared消除了一些控制块需要记录的信息,这样潜在地减少了程序的总内存占用

18、联合体

  • 在查看oc runtime源码发现,原来C++的联合体 union 像结构体一样,可以编写构造函数,有private和public关键字,可以编写方法。。。。。
union aOBJ {
private:
    int value;
public:
    aOBJ(int value = 0){ this->value = value;};
    void say(){  std::cout << "saySomething" << value << std::endl;};
};

19、override关键字

  • C++11 中的 override 关键字,可以显式的在派生类中声明,哪些成员函数需要被重写,如果没被重写,则编译器会报错。
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 204,189评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,577评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,857评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,703评论 1 276
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,705评论 5 366
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,620评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,995评论 3 396
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,656评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,898评论 1 298
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,639评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,720评论 1 330
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,395评论 4 319
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,982评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,953评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,195评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 44,907评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,472评论 2 342

推荐阅读更多精彩内容

  • ^函数重载的匹配: 当函数名被重载后,函数的匹配过程:首先寻找能精确匹配的函数,如果未能精确匹配,则尝试...
    鲁大帅阅读 1,003评论 0 1
  • 本文章分为知识点、例子和心得,交流群728483370,一起学习加油! 3.函数重载 3.1非成员函数重载 3.2...
    程序爱好者阅读 552评论 0 0
  • 第一天 一.内联函数(inline) 函数调用的时候需要建立栈内存环境,进行参数传递,并产生程序执行转移,这些工作...
    陈果123阅读 1,115评论 0 1
  • 1 让自己习惯 C++ 条款01:视 C++ 为一个语言联邦 将C++视为一个由相关语言组成的联邦而非单一语言。在...
    暗夜望月阅读 359评论 0 1
  • 对象和类 面向对象编程(OOP)特性 抽象 封装和数据隐藏 多态 继承 代码的可重用性 访问控制 private,...
    HYIndex阅读 313评论 0 1