基础C++知识
1. 基本模板
#include <iostream>using namespace std;int main(){// 输出cout << "hello naka " << endl;system("pause");return 0;}
2. 注释
3. 变量 常量
- 变量 为一个一定大小的空间取一个名字,方便之后使用
- 常量,定义初始化之后不允许修改
#define、const
4. 关键字
- 修饰符类型:

- 用户标识符区分大小写、见名知意
5. 数据类型
6. 运算符
7. 程序流程结构
- 顺序、选择、循环
- if 、switch 、? : 、 for 、while 、do while
8. 数组
- 数组名,数组名指示该数组在内存中的首地址,普通变量取址符
& - 二维数组定义时,最少给出
int a[][2]= {{1},{1,2}}
9. 函数
- 函数的定义、调用、值传递、声明(被调用的函数写在前面)
- 函数的分文件编写
- 创建
.h后缀的头文件 - 创建
.cpp后缀的源文件 - 在头文件中写函数的声明
- 在源文件中写函数的定义
- 在使用函数的文件中引入该头文件
#include "我的头文件.h"
- 创建
- 函数的默认参数
void func(int a, int b= 10){}- 有默认值的参数必须放在参数列表的后面
-
函数重载
在同一个作用域下;函数名称相同;函数参数类型不同 或者个数不同或 顺序不同
-
10. 指针
定义,使用
int a, *p;p = &a;*p = 1000;// 空指针,用来初始化指针,不能进行访问p = NULL;
常量指针,用const修饰指针
const int * p,指针的指向可以修改,指针所指向的值不可修改- const int * p
- 指针常量,
int * const p,指针的指向不可以改,指针指向的值可以改- int * const p
- 指针和函数(参数)
- 值传递
- 地址传递
11. 结构体
- 定义,使用 ```cpp struct Student { string name; int age; int score; };
struct Student s; // 这里的struct可以省略 s.name = “Naka”;
struct Student s1 = {“Naka”, 41, 98};
2. 结构体数组2. 结构体指针,使用`->`访问成员2. 结构体或结构体指针做函数参数2. 使用const修饰结构体变量的定义,防止误修改<a name="qS4W5"></a>## new操作符1. new的基本语法1. new创建的变量会被存放在堆区,由程序员管理创建与释放1. new返回的是该数据类型的指针1. 使用`delete`关键字释放```cppint *p = new int(10);delete p;
- 使用new创建数组
int *p = new int[10];- 释放数组
delete [] p;
- 释放数组
引用
- 数据类型 &变量2 = 变量1;
- 两个变量操作的是同一个空间
- 引用必须要初始化,指明对谁的引用
- 引用一旦初始化后,就不可更改引用的指向
- 在函数传参时,可以用引用作为形参,这样也可以通过形参来修改实参
引用可以作为函数的返回值
int& test(){static int a = 10;return a; // 返回了a的引用}...int &b = test();cout << b << endl; // 10test() = 1000; // 函数的调用作为等式的左值cout << b << endl; // 1000
引用的原理也是指针常量
类和对象
class Circle { private: double c_r = 10; string c_name;
public: void setName(string name) { c_name = name; } string getName() { return c_name; } void setR(double r) { c_r = r; } double zhouchang() { return 2 PI c_r; } };
int main() { // 实例化 Circle c; c.setName(“圆”); c.setR(11.2); cout << “周长:” << c.zhouchang() << endl;
system("pause");return 0;
}
3. 访问权限:1. 公共`public`1. 保护`protected`,类外不可访问,继承类可以访问1. 私有`private`,类外不可访问,继承类不可以访问1. 默认访问权限为私有<a name="yU6r2"></a>## 构造函数和析构函数1. 编译器自动提供(空实现的),也可以自己写<a name="O6MKt"></a>### 构造函数1. 在创建对象时为对象的成员属性赋值1. `类名(){ }` 没有返回值也不写void,名字与类名相同1. 可以有参数,发生重载2. 两种分类方法:1. 按参数分 有参、无参1. 按类型分 普通、拷贝3. 三种调用方法:1. 括号法1. `Person p1;` 调用默认无参构造函数 注意不加`()`1. `Person p2(10);` 调用有参普通构造函数 将属性值传入1. `Person p3(p2);` 调用有参拷贝构造函数2. 显示法1. `Person p1;` 调用默认无参构造函数 注意不加`()`1. `Person p2 = Person(10);` 调用有参普通构造函数 将属性值传入1. `Person p3 = Person(p2);` 调用有参拷贝构造函数3. 隐式转换法1. `Person p1 = 10;` 相当于`Person p1 = Person(10);`1. `Person p2 = p1;` 相当于`Person p2 = Person(p1);`4. 拷贝构造函数的写法```cppclass Person{string name;Person(const Person &p){name = p.name; // 调用此构造函数的对象会被赋予同p相同的属性值}}
- 拷贝构造函数的调用时机
- 用一个已有的对象来创建一个新对象
- 值传递的方式给函数参数传值
- 值方式返回局部对象
析构函数
- 对象销毁前系统自动调用,执行一些清理工作
~类名(){ }没有返回值也不写void,名字与类名相同,在名称前加~- 不可以有参数
深拷贝与浅拷贝
- 浅拷贝:简单的复制拷贝操作,
int a, b; a = 10; b = a; - 深拷贝:在堆区重新申请空间,进行拷贝操作,
int a = 10; int *b = new int(a);
构造函数初始化列表
- 初始化各个属性值
类名(参数1, 参数2): 属性1(参数1), 属性2(参数2) { }
类对象作为类的成员
静态成员
静态成员变量
- 所有对象共享同一份数据
- 在编译阶段分配内存
-
静态成员函数
定义,在函数的返回类型前加
static,static coid func(){ }- 访问方式
对象名.方法名();类名::方法名();
- 静态方法只能访问静态属性,不能访问其他属性
- 静态成员函数也具有访问权限
所有对象共享同一个静态成员函数
空对象占一个字节(没有一个成员的类对象)
- 静态成员不属于某一个对象,所以静态成员单独存放,不占对象的内存空间
- 成员函数和成员属性也单独存放,只有非静态成员变量属于类的对象上 才占对象的内存空间
this指针
- this指针指向被调用的成员函数所属的对象,用来区分调用该成员函数的对象时哪一个
- this指针隐含在每一个非静态成员函数内,直接使用
- 当形参和成员名相同时,可用this指针来区分
- 在类的非静态成员函数中返回对象本身时,可使用
return *this;```cpp class Person{ public: int age; Person(int age) {
} // 返回引用 !! Person& add10(){this->age = age;
} }this->age += 10;return *this;
// 调用 Person p(10); p.add10().add10();
1. 空指针(`Person *p = NULL;`)可以访问成员函数,需要注意若函数内使用了成员变量(隐含有this指针) 则会出错,否则可以正常访问。<a name="Xnzqu"></a>### const修饰成员函数**常函数**- 成员函数后加const后称为常函数- 常函数内不可以修改成员属性- 成员属性声明时加关键字mutable后,在常函数中依然可以修改```cppclass Person{public:int age;Person(int age) {this->age = age;}void func() const {age = 10; // 出错}}
- this指针的本质是一个指针常量
Person * const this;其指向不可以修改 - 在成员函数后加上const后,就把this指针变成了常量指针
const Person * const this;其指向的值也不可以修改
常对象
- 声明对象前加const称为常对象
const Person p; - 常对象只能调用常函数,因为普通成员函数可以修改成员属性
- 其属性不允许被修改,否则在成员属性的定义前加mutable
友元
全局函数做友元
- 让一个全局函数可以访问一个类的私有成员
```cpp
class Person {
friend void personFriend(Person* p); // 声明该全局函数为友元
private:
int age;
public:
Person(int age) {
} };this->age = age;
// 全局函数做友元 void personFriend(Person* p) { cout << “全局函数做友元 访问私有属性值:” << p->age << endl; }
void test() { Person p(40); personFriend(&p); }
<a name="uQDzl"></a>### 类做友元- 让一个类可以访问另一个类的私有成员```cppclass Person {friend class Chinese; // 声明为友元private:int age;public:Person(int age) {this->age = age;}};// 类做友元class Chinese {public:Person* p;Chinese() {p = new Person(30);}void visit() {cout << "类做友元 访问私有属性 " << p->age << endl;}};void test() {Chinese c;c.visit();}
成员函数做友元
- 让一个类的部分成员函数可以访问另一个类的私有成员
- 前向声明,告诉编译器有这么一个类,但编译器不知道其大小 也不能访问。声明、预定使用、定义、使用 ```cpp class Person; // 前向声明该类,但具体使用还是只能在类定义之后
// 成员函数做友元 class Japanese { private: Person* p; // 预定使用 public: int m_age; Japanese(int age); // 在类外实现 void visit(); }; class Person { friend void Japanese::visit(); // 声明为友元 private: int age; public: Person(int age) { this->age = age; } }; // 在类外实现成员函数,因为要在前向声明的类定义之后 Japanese::Japanese(int age) { m_age = age; p = new Person(age); } void Japanese::visit() { cout << “成员函数做友元 访问私有属性 “ << p->age << endl; } void test() { Japanese j(20); j.visit(); }
<a name="NruPE"></a>## 运算符重载**概念**:对已有的运算符重新进行定义,赋予其另一种功能,以适应不同的数据类型<br />要用了再学<a name="m6lgo"></a>## 继承**优点**:代码复用<br />**语法** 定义子类时,`class 子类: 继承方式 父类{ };`- 子类 - 派生类- 父类 - 基类- 构造与析构的顺序,创建子类对象时- 父类构造 -> 子类构造 -> 子类析构 -> 父类析构- 当子类和父类的成员属性`m_A`同名时,使用子类对象`Son s;`直接访问`s.m_A;`的是子类成员属性,外加父类作用域`s.Base::m_A`才能访问父类成员属性,访问父类的同名成员函数`s.Base::func();`<a name="vIswq"></a>### 继承方式1. 公共继承 `public`1. 保护继承 `protected`1. 私有继承 `private`| 父类 | 子类1(公共继承) | 子类2(保护继承) | 子类3(私有继承) || --- | --- | --- | --- || 公共权限成员 | 公共权限 | 保护权限 | 私有权限 || 保护权限成员 | 保护权限 | | || 私有权限成员 | 不可访问 | | |4. 父类的私有成员在子类中即使不能被访问,但还是被继承了。<a name="LGAhj"></a>### 多继承**语法**:`class 子类: 继承方式 父类1, 继承方式 父类2{ };`1. 当多个父类中存在同名的成员时,子类访问时需要加作用域区分1. 菱形继承时,可能存在数据浪费(两个父类存在同名的数据,子类无法确定是使用父类1的数据还是父类2的数据)1. 解决,使用**虚继承**,在继承之前加关键字`virtual````cppclass Animal{public:int m_age;}class Sheep: virtual public Animal{ };class Tuo: virtual public Animal{ };class SheepTuo: public Sheep, public Tuo{ };SheepTuo st;st.Sheep::m_age = 100;st.Tuo::m_age = 200;cout << st.m_age << endl; // 200
多态
两类:
- 静态多态,函数重载、运算符重载 函数地址早绑定 - 编译阶段确定函数地址
- 动态多态,派生类、虚函数实现运行时多态 函数地址晚绑定 - 运行阶段确定函数地址
class HomePage {public:// 虚函数virtual void contain() {cout << "主页面中间" << endl;}};class MyPage: public HomePage {public:// 重写父类的虚函数void contain() {cout << "我的页面中间" << endl;}};void doDraw(HomePage &hp) { // 子类可以自动转化为父类hp.contain();}void test(){MyPage mp;doDraw(mp); // 没加virtual 主页面,加了virtual 我的页面,根据传入的对象调用}
动态多态实现条件
- 有继承关系
- 子类重写父类中的虚函数
多态使用:父类指针或引用指向子类对象
