C++知识总结
大端小端
对于0x0110
大端(大端放在低地址):0x01放在低地址
小端(小端放在低地址):0x10放在低地址
NULL与nullptr
NULL: 也就是0,可以赋值给int;int a = NULL;
nullptr: 该关键字只能赋值给指针 int *p= nullptr;
实例化对象
// 栈中实例化对象,内存自动释放,调用方式:.
Worker worker;
// 堆中实例化对象,内存需手动释放,调用方式:->
Worker *p = new Worker();
delete p;
p = NULL;
构造函数与析构函数
构造函数:在对象实例化时被调用,无返回值。函数名与类名相同,可以是有参数的函数
析构函数:在对象销毁的时候调用
赋值构造函数:也叫拷贝构造函数
类型转换构造函数:只有一个参数,实现类型的自动转换
class Complex {
public:
double real, imag;
Complex(int i) {};
Complex(double r, double i) {
real = r;
imag = i;
}
};
Complex::Complex(int i) { // 类型转换构造函数
cout << "intConstructor called" << endl;
real = i;
imag = 0;
}
int main() {
Complex c1(7, 8); // 初始化构造函数,直接构造
Complex c2 = 12; // 调用类型转换构造函数
c1 = 9; // 调用类型转换构造函数,9被自动转换为一个临时对象
return 0;
}
// relsut:
intConstructor called
intConstructor called
父类子类数据访问
- 父类数据访问
对象实例禁止访问类中的private和protected的数据成员
类内可以访问 - 子类数据访问
子类可以访问父类中的protected成员
子类禁止访问父类中的private成员
this指针
从C++程序到C程序的翻译,可以知道,C只有全局的函数,要使得某个成员函数与类关联起来,需要this
重要:在非静态函数中,this指针是指向函数作用对象的指针
class Complex {
public:
double real, imag;
Complex(double r, double i):real(r),imag(i){}
void Print() {
cout << "real:" << real << ", imag:" << imag << endl;
}
Complex AddOne(){
this->real++;
return *this;
}
};
int main() {
Complex c1(7, 8);
c1.Print();
c1.AddOne();
c1.Print();
return 0;
}
// result:
real:7, imag:8
real:8, imag:8
指针与引用
- 指针
指针常量:不能再指向别地址
常量指针:指向常量的指针,指向的内容不能通过指针进行修改
指针数组:存放指针的数组
数组指针:指向数组的指针
// 指针常量
int a = 3; int b = 4;
int *const p = &a;
p = &b; // 错误, p不能再更改;
// 常量指针
int a = 3;
const int *p = &a;
*p = 40; // 出错, 不能编译
a = 40; // 这样可以
// 指针数组
int *Arr[10]; // 变量名arr先与[]组合是数组
// 数组指针
int (*p)[10]; // 变量名p先与*组合是指针
// 指针指向数组
int arr[] = {1, 2, 3, 4};
int * p = arr;
*(p + 2) => arr[2]; // 通过指针访问元素
- 引用
引用(变量的别名)必须初始化:要有实际的变量名。int &b = a;
a是变量名
const
作用:
- 修饰变量;该变量不可以改变,该变量需要进行初始化
const int a = 0;
- 修饰指针;前置条件
int a = 0; int b = 1;
指向常量的指针 | 指针常量 |
---|---|
const int *p = &a; | int * const p = &a; |
*p = 80; 修改指向的常量会报错 | p = &b; 修改指针的指向会报错 |
- 修饰函数参数;可以将非const的实参传给const修饰的参数,只需要保持函数内不变即可
- 修饰成员函数
- const修饰的成员函数内部不能修改任何成员变量
- const修饰的成员函数不能调用非const成员函数
// const的使用
// 类
class A
{
private:
const int a; // 常对象成员,只能在初始化列表赋值
public:
// 构造函数
A() : a(0) { };
A(int x) : a(x) { }; // 初始化列表
// const可用于对重载函数的区分
int getValue(); // 普通成员函数
int getValue() const; // 常成员函数,不得修改类中的任何数据成员的值
};
void function()
{
// 对象
A b; // 普通对象,可以调用全部成员函数、更新常成员变量
const A a; // 常对象,只能调用常成员函数
const A *p = &a; // 指针变量,指向常对象
const A &q = a; // 指向常对象的引用
// 指针
char greeting[] = "Hello";
char* p1 = greeting; // 指针变量,指向字符数组变量
const char* p2 = greeting; // 指针变量,指向字符数组常量
char* const p3 = greeting; // 自身是常量的指针,指向字符数组变量
const char* const p4 = greeting; // 自身是常量的指针,指向字符数组常量
}
// 函数
void function1(const int Var); // 传递过来的参数在函数内不可变
void function2(const char* Var); // 参数指针所指内容为常量
void function3(char* const Var); // 参数指针为常量
void function4(const int& Var); // 引用参数在函数内为常量
// 函数返回值
const int function5(); // 返回一个常数
const int* function6(); // 返回一个指向常量的指针变量,使用:const int *p = function6();
int* const function7(); // 返回一个指向变量的常指针(自身是常量的指针),使用:int* const p = function7();
重载与重写
重载:函数名相同,参数不同;没有继承关系
void func();
void func(int a);
重写:对虚函数重写;有继承关系
运算符重载
解决的问题:利用+、-等运算符对类的对象进行计算,否则需要操作成员函数进行计算
class Dollar {
public:
int yuan = 0;
int cent = 0;
Dollar operator + (const Dollar & dollar);
Dollar(int _yuan, int cent);
};
Dollar Dollar::operator+(const Dollar &dollar)
{
Dollar dollarRes(0, 0);
int c = dollar.cent + cent;
dollarRes.cent = c % 100;
int d = dollar.yuan + yuan;
dollarRes.yuan = d + c / 100;
return dollarRes;
}
Dollar::Dollar(int _yuan, int _cent) {
yuan = _yuan;
cent = _cent;
}
int main()
{
Dollar dol(10, 5);
Dollar dol1(10, 95);
Dollar dor = dol + dol1;
printf("yuan:%d, cent:%d\n", dor.yuan, dor.cent);
}
// result:
yuan:21, cent:0
封装
- 初始化列表
- 初始化列表先于构造函数执行
- 初始化列表只能用于构造函数
- 初始化列表可以同时初始化多个数据成员
class Coordinate{
public:
Coordinate(int x, int y);
private:
const int m_iX;
const int m_iY;
};
// 在进行Coordinate方法实现的时候,由于private中的const
// 直接使用会出错Error
Coordinate::Coordinate(int x, int y){
m_iX = x;
m_iY = y;
}
// 这里要进行正确的实现
// 需要使用初始化列表
Coordinate::Coordinate(int x, int y):m_iX(x), m_iY(y){}
继承
class Person{
public:
void eat();
string m_strName;
int m_iAge;
};
// 公有继承
class Woker:public Person
{
public:
// void eat(); // 基类已经包含,可以不写
void work();
// string m_strName; // 基类已经包含,可以不写
// int m_iAge; // 基类已经包含,可以不写
int m_iSalary;
};
// 使用
int main(void){
Worker worker;
worker.m_strName = "Merry";
worker.eat();
return 0;
};
- 共有继承、保护继承、私有继承
- 多重继承、多继承、虚继承
多重继承:
多继承:
虚继承:用于解决菱形继承问题
// 虚继承
// 用于解决菱形继承问题
class Worker:virtual public Person
{
};
class Farmer:virtual public Person
{
};
class MigrantWorker:public Worker,public Farmer
{
};
多态
静态绑定:编译时的多态,由函数重载来实现
动态绑定:运行时的多态,由虚函数来实现(virtual关键字)
多态具体到语法中是指,使用父类指针指向子类对象,并可以通过该指针调用子类的方法
原理:虚函数表,定义了虚函数的类含有虚函数表,类对象有虚函数表指针,指向虚函数表。子类继承后,首先会继承虚函数表,如果子类进行重写后,使用重写后函数的地址来覆盖原地址
虚析构函数:为了避免使用父类指针释放子类对象时造成内存泄露。
// 虚析构函数的使用
class Shape
{
public:
Shape(); // 构造函数不能是虚函数
virtual double calcArea();
virtual ~Shape(); // 虚析构函数
};
class Circle : public Shape // 圆形类
{
public:
virtual double calcArea();
...
};
int main()
{
Shape *shape1 = new Circle(4.0);
shape1->calcArea();
delete shape1; // 因为Shape有虚析构函数,所以delete释放内存时
// 先调用子类析构函数,再调用基类析构函数
// 防止内存泄漏。
shape1 = NULL;
return 0;
}
虚函数/纯虚函数和抽象类/接口类
- 虚函数
- 含有virtual关键字,没有
= 0
;函数声明可以有函数定义也可以没有函数定义 virtual double calcArea() { return 0; }
- 含有virtual关键字,没有
- 纯虚函数
- 只有函数声明,没有函数定义的虚函数
virtual double calcPerimeter() = 0;
- 抽象类
- 含有纯虚函数的类
- 抽象类无法实例化对象
- 抽象类的子类也可以是抽象类
- 子类没有对纯虚函数进行实现
- 子类中含有新的纯虚函数
- 接口类:更多的表达是一种协议或者能力
- 只有纯虚函数的类
- 类中无数据成员、只有成员函数(成员函数都是纯虚函数)
dynamic_cast
- 只能应用于指针和引用的转换
- 要转换的类型中必须包含虚函数
- 转换成功返回子类的地址,失败返回NULL
友元函数
定义在类外部,但有权访问类的所有私有成员与保护成员
#include <iostream>
using namespace std;
class Box
{
double width;
public:
void setWidth(double wid);
friend void printWidth(Box box);
};
// 成员函数定义
void Box::setWidth(double wid)
{
width = wid;
}
// 请注意:printWidth() 不是任何类的成员函数
void printWidth(Box box)
{
/* 因为 printWidth() 是 Box 的友元,它可以直接访问该类的任何成员 */
cout << "Width of box : " << box.width <<endl;
}
// 程序的主函数
int main( )
{
Box box;
box.setWidth(10.0); // 使用成员函数设置宽度
printWidth(box); // 使用友元函数输出宽度
return 0;
}
智能指针
- unique_ptr:通过封装指针为栈对象(栈对象生命结束后,自动释放),不能被多个实例共享内存
std::uniqie_ptr<A> p1(new A());
- shared_ptr:多个指针可通过计数的方式共享.
std::shared_ptr<A> p1 = std::make_shared<A>();
std::shared_ptr<A> p2 = p1
- weak_ptr:当存在循环引用的时,shared_ptr无法释放,会造成死锁
std::weak_ptr<A> a;
内存
lock_guard和unique_lock
内置宏
__LINE__ # 代码所在行号
__FUNCTION__ # 代码所在函数
__FILE__ # 代码所在文件
(long)getpid() # 获取进程号