C++学习笔记

## 换行

endl与\n都表示换行

string 表示字符串

````cpp

string mytext="Hello";

````

## 常量

const 表示常量

声明后不可修改

````cpp

const a=10;

a=12;

cout<<a;  输出a=10;

#define b 6

cout<<b;  输出b=6;  

````

## 关键字

 int  double string auto bool等为关键字,在声明变量时,不可以用关键字作为变量

## 标识符(变量、常量名)命名规则

1.不可以是关键字

2.由字母、数字、下划线构成

3.标识符第一个字母只能是字母或下划线

4.标识符是区分大小写的

## 数据类型

### 整型

1、short 短整型  2byte          -2^15~2^15-1  -32768 ~ 32767

2、int 整型     4byte           -2^31~2^31-1

3、long 长整型     windows 4byte     linux 32位4byte 64位8byte

4、long long 长长整型  8byte    -2^63~2^63-1

sizeof() 可以统计数据类型所占的内存大小

### 浮点型(实型)

1、float    4byte   7位有效数组

2、double   8byte   15~16位有效数字

编译器会默认小数为double型  float型会在数字后面加f  

float a=3.14f;

小数最多表示6为有效数字,如果要查看更多的有效数字,需要配置

科学记数法表示小数:

float s2=3e2  如果e后是正数,代表3*10^2=3*10*10=300;

float s2=3e-2 如果e后是负数,代表3*0.1^2=3*0.1*0.1

### 字符型

char a='a'; 创建字符型变量要用单引号,且只能有一个字符

### 字符串

string str="hello world"

输出时,需要包含 <string> 头文件

### 逻辑运算

&& 与

|  或

! 非


 

### 函数重载情况下 如果体语句有默认值,会有二义性,要避免默认值

void func(int a,int b=10);

void func(int a);

如果主函数内调用时

func(a),则两个函数都符合,所以要避免这种情况

### 内存

#### 四区

代码区:存放函数的二进制代码,由操作系统进行管理

代码区是共享  只读的

全局区:存放全局变量 静态变量 常量

全局变量 static静态变量 常量 const修饰的(全局)变量 字符串常量

在全局区,这个取余的数据由操作系统来管理释放

栈区:由编译器自动分配释放,存函数参数值 局部变量等

不要返回局部变量的地址,

int func()

{

    int a=10;

    return &a;

}

int main()

{

    int *p=func();

}

cout<<*p;

cout<<*p;

这段代码打印时,只有第一次可以正常打印,因为局部变量在释放时,编译器会保留一次,但是第二次就不再保留了

堆区:由程序员分配释放 若程序员不释放,则结束时由操作系统回收

new 可以在堆区开辟数据  

int *p= new int(10);

new 返回的是一个数据类型的指针

new 开辟数组

int *arr= new int[20];//数组内有10个元素,返回值为线性空间的首地址

delete可以手动释放内存

delete p;

delete[] arr;

## 面向对象的三大特征 :封装 集成 多态

封装的意义:

1、将属性和行为作为一个整体

2、将属性和行为加以权限控制

访问权限:

1、 public

2、 protected  儿子可以访问父亲的保护内容

3、 priavte    儿子也不可以访问

class如果不标注  默认权限为私有权限

struct 默认权限为公共权限

### 类和对象

#### 构造函数和析构函数

构造函数:用于在创建对象时为对象的成员属性赋值,构造函数由编译器自动调用,无需手动调用

析构函数:用于在对象销毁前系统自动调用,执行一些清理工作。

如果不写构造函数和析构函数,编译器会提供,但是为空实现(没有内容)

由编译器自动调用一次

语法:

无返回值,函数名与类名相同,可以有参数,

Cube()

{

    cout << "构造函数的调用" << endl;

}

无返回值,函数名与类名相同,前加一个 ~ 不可以有参数,所以不会发生重载

~Cube()

{

    cout << "析构函数的调用" << endl;

}

#### 构造函数的分类和调用

按参数分为: 有参构造和无参构造(默认构造函数)

按类型分为: 普通构造和拷贝构造

//拷贝构造函数

Person(const Person &p)

{

}

//拷贝构造函数的调用时机

//1.使用一个已经创建完毕的对象来初始化一个新对象

//2.值传递的方式给函数参数传值

//3.值方式返回局部对象

三种调用方式:括号法 显示法 隐式转换法

显示法

Person p1=Person(10);

Person(10); 被称为匿名对象 特点:当前行执行结束后,系统直接回收掉

默认情况下,c++编译器至少会给一个类添加4个函数

1.默认构造函数(无参)

2.默认析构函数

3.拷贝构造函数,对属性进行值拷贝

4.赋值运算operator=对属性进行值拷贝

如果用户定义有参构造函数,则编译器不再提供无参构造

用户定义拷贝构造函数,编译器不再提供其他构造函数

深拷贝 和 浅拷贝

浅拷贝:简单的赋值操作

深拷贝:在堆区申请空间,进行拷贝操作

如果浅拷贝,则会引起堆区内存重复释放

如果属性有在堆区开辟的,则需要自己写拷贝函数

初始化列表

Person():属性(),属性() ...

{

}

#### 类的对象作为成员

class A{}

class B{

    A a;

}

当其他类的对象作为本类成员,构造时,先构造本类的对象,再构造自身,  先构造A,再构造B

析构时,先析构本身,在析构对象  先析构B,再析构A

#### 静态成员

在成员变量和成员函数前加上关键词static 称为静态成员

静态成员变量:

所有对象共享同一份数据

在编译阶段分配内存(全局区)

类内声明,类外初始化

静态成员变量不属于某个对象,所有对象共享一份数据

因此有两中访问方式

1、通过对象访问

p.m_a;

2、通过类名访问

Person::m_a;

静态成员变量也有访问权限

私有权限类外访问不到

静态成员函数

所有对象共享一个函数

静态成员函数只能访问静态成员变量,因为无法分清是哪个对象的变量

只有非静态的成员变量才属于对象

空对象的内存空间是一个字节 分配这一个字节是为了区分空对象在内存的位置

非空对象的内存空间 就是非静态成员变量的大小,原先1内存的空对象大小会被释放

静态成员变量(函数)的空间不会被记入对象,

因为静态成员变量(函数)不属于类对象

非静态成员函数也不属于类对象上

只有非静态成员变量数类的对象

#### this指针

只有非静态成员变量数类的对象

静态成员变量和成员函数以及非静态成员函数都不属于类对象

this指针指向被调用的成员函数所属的对象

this指针隐含在每一个非静态成员函数

不需要定义,直接用即可

用途:

当形参和成员变量同名时,可以用this指针来区分

来类的非静态成员函数返回对象本身时,可以用 return *this

空指针访问成员函数时,如果成员函数没有用到成员变量,则可以访问

在成员函数后加const,我们称为常函数

长函数不可修改成员属性

成员属性声明时,加关键字mutable,则常函数中可以修改

常对象

如果在对象前加const 则成为常对象 常对象只能调用常函数

// this指针本质是指针常量 Person * const this  

//在成员函数后加const 修饰的是this的指向,使其指向的值也不可以修改

//但是 在变量前加 mutable 则常函数也可以修改变量

void showPerson() const

{

    this->age = 20;

}

int a;

mutable int age;//特殊变量 ,常函数可以修改

//常对象,其中的值不可以修改,但是mutable修饰的变量可以修改

const Person p1(10);

//常对象这只能调用常函数、

p1.showPerson();

### 友元

友元的目的:让一个函数或类访问另一个类中的私有成员

友元的三种实现:

1.全局函数做友元

2.类做友元

3.成员函数做友元

1.

一个全局函数访问私有成员时,需要在类的开头声明友元函数,

class Building

{

    //友元函数  

    friend  void GoodGay(Building* building);

}

2.友元类GoodGay可以访问私有成员:卧室

class Building

{

    //友元类

    friend class GoodGay;

public:

    Building();

    string m_sittingroom;//客厅

private:

    string m_bedroom;//卧室

};

//类外写成员函数

Building::Building()

{

    m_sittingroom = "客厅";

    m_bedroom = "卧室";

}

3.成员函数做友元

在声明两个类时,如果一个类在前,但是其中有后面类的变量或内容,就需要前向声明

class Building;

class GoodGay

{

public:

    Building * building;//如果没有前向声明就会报错

};

但是如果调换building和goodgay的顺序依然会报错

GoodGay 类需要 Building 的完整定义,而 Building 又需要 GoodGay 的完整定义

这是一个 循环依赖 问题,需要调整代码顺序来解决。

class GoodGay;

class Building

{

    //编译器无法知道visit函数

    //虽然你前向声明了 class GoodGay;,但前向声明只告诉编译器 GoodGay 是一个类,而不会提供其成员函数的声明。

    friend void GoodGay::visit();

}

### 运算符重载

可以对 + - 等运算符进行 自定义数据类型 的运算

只可以重载 自定义的数据类型   但是内置数据类型不可以重载,如int double 等,运算符不可重载

成员函数重载运算符

Person operator+(Person &p)

全局函数重载运算符

Person operator+(Person &p1,Person &p2)

p3=p2+p1

也可以Person operator+(Person &p1,int a)

p3=p1+10

但是 成员函数的运算符重载 不可以写为,只有全局函数可以将非类的数据类型做为左值

p3=10+p2

这是因为成员函数的第一个参数是隐式的 this 指针,它指向调用该函数的对象(必须是类类型)。因此,成员函数重载的运算符无法将非类类型作为左操作数。

//成员函数重载左移运算符 p.operator<<(cout)  简化版本 p<<cout

//不会利用成员函数重载<<,因为无法实现 cout 在左侧

左运算符是ostream类型

ostream& operator<<(ostream & cout, Person& p)

{

    cout << "m_a:" << p.m_a << "m_b:" << p.m_b << endl;

    return cout;

}

如果访问有私有成员 则可以利用友元技术访问私有成员

friend ostream& operator<<(ostream & cout, Person& p);

//如果不用 & 符号,则在cout << ++(++myint) << endl;

// ++myint后,再次++的对象变为拷贝值,而不是myint本身,

//返回的是 & 后,就可以一直对一个数据进行操作

//前置运算

myinteger& operator++()

{

    m_num++;

    return *this;

}

//后置运算

//int 代表展位参数,可以用于区分前置和后置

//后置递增不需要 返回&

 myinteger operator++(int)

{

    //先记录当前结果

    myinteger temp = *this;

    //后递增

    m_num++;

    //返回记录结果

    return temp;

}

赋值运算符重载用于在堆区开辟内存的变量的赋值 (将浅拷贝 变为 深拷贝)

如果类的变量开辟在堆区,然后再用赋值操作,P1=P2则P2的变量和P1的变量指向同一块堆区内存,在析构时就会对同一区域释放两次,造成程序崩溃

#### 函数调用运算符重载

函数调用运算符()也可以重载

由于重载后使用的方式非常像函数的调用,因此被称为仿函数

仿函数没有固定写法,非常灵活

多用于stl

void operator()(string test)

{  

    cout << test << endl;

}

p1("chenxi");//由于使用起来非常像函数,所以被称为仿函数

myadd a1;

int ret = a1(100, 100);

cout << ret << endl;

cout << myadd()(10, 10) << endl;

myadd() 匿名对象显示创建,

myadd()(10, 10) 仿函数重载

## 继承

继承的好处:减少重复代码

语法: class 子类 :继承方式 父类

子类 也称为 派生类

父类 也称为 基类

继承的继承方式:

公共继承

保护继承

私有继承

父类的private 子类无论以那种方式都访问不到

公共继承 父类内的 公共和保护的成员 权限不改变

保护继承 父类内的 公共和保护的成员 全变为保护权限

私有继承 父类内的所有成员 全变为子类的私有权限

#### 继承中的对象模型

父类中所有的非静态成员 无论什么权限,都会被子类继承下去,

私有成员被编译器因此,访问不到,但是确实被继承了

开发人员命令提示工具 developer...

  c1 /dl reportSingClassLayout类名 文件名

  可以查看对象模型

子类和父类继承中 构造和析构顺序

base 构造

son 构造

son 析构

base 析构

#### 继承中 同名成员处理方式

1、访问子类同名成员  直接访问

2、访问父类同名成员  需要加作用域

//如果子类和父类出现同名的成员函数,子类的同名成员函数会隐藏掉父类的

//通过子类访问父类的同名成员函数 需要加作用域

继承中 子类不要写和父类一样的成员变量

静态成员处理方式:

静态成员变量

//通过对象访问

son s1;

cout<< s1.m_b <<endl;

//通过子类访问父类的同名成员 需要加作用域

cout << s1.base::m_b << endl;

//通过类名访问

//son::表示 通过类名方式访问  base:: 表示访问base类的内容

cout << son::base::m_b << endl;

cout << son::m_b << endl;

静态成员函数:

s1.func3();

son::func3();

s1.base::func3();

son::base::func3();

#### 多继承语法

语法: class: 继承方式 父类1,继承方式 父类2,....

多继承也可能会引发同名问题,在同名时需要加作用域

如果base1  base2 都有m_a

使用时需要加作用域

cout<<s.baes1::m_a;

cout<<s.baes2::m_a;

在开发中不建议使用多继承

#### 菱形继承

两个派生类继承了同一个基类

又有一个类继承了两个派生类

这种继承叫做菱形继承 也叫钻石继承

//利用虚继承 可以解决菱形继承的问题

class sheep :virtual public animal

v       b    ptr 虚基类指针

virtual base pointer

虚基类指针会指向 vbtable

virtual base table

## 多态(继承中 子类不要写和父类一样的成员变量)

多态分为两类

静态多态:函数重载、运算符重载、复用函数名

动态多态:派生类和虚函数实现运行时多态

区别:

静态的函数地址早绑定,编译阶段确定函数地址

动态的函数地址晚绑定,运行阶段确定函数地址

virtual void speak() 虚函数可以实现晚绑定

动态多态满足条件:

1、有继承关系

2、子类重写父类中的虚函数

类中只有一个虚函数时,类会有一个占4字节大小的指针 vfptr 虚函数(表 )指针

virtual function pointer

指向虚函数表 vftable 该表记录虚函数地址

子类会继承这个虚函数指针,

当子类重写了这个虚函数, 子类中的虚函数表会替换成 子类的虚函数地址

当父类的指针 或引用  指向子类对象时, 发生多态

animal &animal =cat

虚函数会去找传入类的虚函数表

多态好处:

组织结构清晰  出错可以定位确定的代码段

可读性强

对前期和后期的扩展和维护性高

### 纯虚函数 抽象类

通常父类的虚函数的实现时毫无意义的,称为纯虚函数

当类中有了纯虚函数  就成为抽象类

抽象类的特点:

无法实例化函数

子类必须重写抽象类的纯虚函数,否则也属于抽象类

### 虚析构和纯虚析构

多态时,子类如果有属性开辟到堆区,父类释放时无法调用到子类的虚构代码

解决方式就是析构改为虚析构或纯虚析构

    //父类指针在析构时,不会调用子类的析构函数

    //子类如果有堆区的属性,会造成内存泄露

    virtual~animal()

{

    cout << "animal xi gou " << endl;

}

父类为虚析构时,就可以解决释放不干净的问题

class animal

{

    ------

    virtual~animal() = 0;

};

animal::~animal()

{

    cout << "animal chun xu xi gou " << endl;

}

纯虚析构需要有声明 也需要具体实现

有了纯虚析构 也属于抽象类

## 文件操作

#include<fstream>

    //1.包含 ftream头文件

   

    //2.创建流对象

    ofstream ofs;

    //3.指定打开方式

    ofs.open("test.txt",ios::out);

    //4.写内容

    ofs << "chenxi" << endl;

    //5.关闭文件

    ofs.close();

文件打开方式:

ios::in     为读文件而打开文件

ios::out    为写文件而打开文件

ios::ate    初始位置:文件尾

ios::app    追加方式写文件

ios::turnc  如果文件存在先删除,在创建

ios::binary 二进制方式


 

case 语句过长 需要把下面包括break的语句括起来

# 模板 泛型编程 STL

## 函数模板

模板调用规则:

如果函数模板和普通函数都可以实现,优先调用普通函数

可以通过空模板参数列表来强制调用函数模板

函数模板也可以发生重载

函数模板可以产生更好的匹配,优先调用函数模板

通过模板重载,可以为具体类型提供具体化的模板

## 类模板

类模板没有自动类型推导的使用方式,

类模板参数列表可以有默认参数

类模板在创建成员时,可以调用其他类的函数,

然后

在创建具体的类时,

该类有哪个成员函数才能调用哪一个

成员函数的调用时机:

类模板中的成员函数并不是一开始就创建的,在 调用时 才会确定是哪个具体的类 才会去创建

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值