快速复习一遍C++基础知识点

暂定月计划:1实现DSA基础算法 2完成一个STL库 3在Linux上加强相关知识 4git巩固 5OJ增强代码实现能力
今天先快读复习一遍C++知识点,(想把peral读完==)


1 引用

  1. 交换两个数示例:
    C语言中:
void swap(int *a, int* b)
{
	int tmp;
	tmp = *a; *a = *b; *b = tmp;
}
int n1, n2;
sawp(&n1, &n2);//n1,n2的值被交换

C++中用引用

void sapw(int &a, int &b)
{
	int tmp;
	tmp = a; a = b; b=tmp;
}
int n1, n2;
sapw(n1, n2);
  1. 引用作为函数的返回值
int n = 4;
int& SetValue() {return n;}
int main()
{
	SetValue() = 40;
	cout<<n;
	return 0;
}
  1. 常引用
    定义引用时,前面加const关键字,即为常引用;不能通过常引用去修改其引用的内容;但并不是说它引用的内容就不能被修改,是可以通过其他方式被修改的 (跟常量指针一个道理,不能通过常量指针修改内容)
int n = 100;
const int & r = n;//常引用
r = 200;//编译错
n = 200;//没问题
  1. const T &T&
    T &类型的引用或者T类型的变量可以用来初始化const T &类型的引用,反之不可以,除非用强制类型转换;同理,不能把常量指针赋值给非常量指针,而反之可以,除非强制类型转换;
    常常会在函数内将函数参数定义为常量指针,就可以避免函数内部不小心改变参数指针所指地方的内容

2 动态内存分配

new运算符实现动态内存分配,(在C中用malloc分配)
方法1:

P = new T;

T是任意类型名,P是类型为T*的指针;动态分配出一片大小为sizeof(T)字节的内存空间,并且将该内存空间的起始地址赋值给P

int *pn; pn = new int; *pn = 5;

方法2:

P = new T[N];

分配出N* sizeof(T)的内存空间,并将该内存的起始地址赋值给P

delete运算符进行释放,必须指向new出来的空间,注意一个空间不能被delete多次,举例delete释放动态分配的数组:

int *p = new int[20];
p[0] = 1;
delete[] p;//删除new出来的一个数组一定要加一个[]

3 内联函数、函数重载、函数缺省参数

  1. 内联函数
    函数调用是有时间开销的,如果函数本身只有几条语句,执行非常快,那么当这样简单的函数被反复执行很多次的时候,相比之下调用函数函数所产生的开销反而显得比较大。
    (在调用一个函数时,首先要把参数、返回地址放入到栈中,当函数执行完需要从栈里取出返回地址,再跳转到返回地址去执行,这些都是额外的开销)
    为了减少函数调用的开销,引入了内联函数机制。编译器处理对内联函数的调用时,是将整个函数的代码插入到调用语句处,就不会产生调用函数的语句。 在函数前加inline关键字;

  2. 函数重载
    一个或多个函数,名字相同,然而参数个数或者参数类型不相同,为函数重载;函数重载使得函数命名变得简单了。编译器根据调用语句中的实参的个数和类型判断应该调用哪个函数

  3. 函数的缺省参数
    C++中,定义函数的时候可以让最右边的连续若干个参数有缺省值,那么调用函数的时候,若相应位置不写参数,参数就是缺省值

void func(int x1, int x2 = 2, int x3 = 3){}
func(10);//等效于func(10,2,3)
func(10,,8);//不行,只能最右边的连续若干个参数缺省

函数重载目的是为了提高程序的可扩充性
即如果某个写好的函数要添加新的参数,而原先那些调用函数的语句,未必需要使用新增的参数,那么为了避免对原先那些函数调用语句的修改,就可以使用缺省参数√

构造函数

成员函数的一种,名字与类名相同,可以有参数,不能有返回值(void也不行);作用是对对象进行初始化,如对成员变量赋初值;但注意对象所占用的存储空间并不是构造函数分配的,构造函数只是在对象已经占了内存空间后做一些初始化的工作
类一定有构造函数,如果定义类时没有写构造函数,则编译器生成一个默认的无参数的构造函数,不做任何的操作;一个类可以有多个构造函数(函数重载);但一旦有了自己定义的构造函数,编译器便不产生无参数的默认构造函数了,如果有需要无参的,就需要自己写了;
对象生成时构造函数会被自动调用,但注意对象一旦生成,就再也不会再在其上执行构造函数了

复制构造函数

只有一个参数,即对同类对象的引用
如:X::X(X&)X::X(const X&),二者选一,参数必须是引用不能是对象,后者能以常量对象作为参数;更多情况下会用第二种形式,因为一般情况下都不会去修改实参的值
如果没有定义复制构造函数,那么编译器会生成默认的拷贝构造函数

复制构造函数起作用的三种情况:

  1. 当用一个对象去吃书画同类的另一个对象时
Complex c2(c1);
Complex c2 = c1;//这是初始化语句,不是赋值语句
  1. 如果某函数有一个参数是类A的对象,那么该函数被调用时,类A的复制构造函数将被调用
  2. 如果函数的返回值是类A的对象时,则函数返回时,A的复制构造函数被调用

类型转换构造函数

1定义转换构造函数的目的是实现类型的自动转换;
2 只有一个参数,而且不是拷贝构造函数的构造函数,一般就可以看做是转换构造函数;
3当需要的时候,编译系统会自动调用转换构造函数,建立一个无名的临时对象(或临时变量)(编译器对临时对象操作)

析构函数

  1. 加~;没有参数和返回值,一个类最多只能有一个析构函数
    析构函数对象消亡时即自动被调用,可以定义析构函数来在对象消亡前做如释放分配空间的工作;
    如果定义类时没写析构函数,则编译器生成缺省析构函数,缺省析构函数什么也不做
  2. 在数组中,对象数组生命期结束时,对象数组的每个元素的析构函数都会被调用
    举例:
class Ctest
{
public:
	~Ctest(){cout<<"析构调用"<<endl;}
};
int main()
{
Ctest array[2];
cout<<"结束mian"<<endl;
return 0;
}
/*
输出结果:
结束main
析构调用
析构调用
*/
  1. 关于析构函数和运算符delete
    delete运算符导致析构函数调用
Ctest *pTest;
pTest = new Ctest;//构造函数被调用
delete pTest;//析构函数被调用
//
pTest = new Ctest[3];//构造函数调用3次
delete [] pTest;//析构函数调用3次

若new一个对象数组,在delete时不用[],那么只调用一次析构函数,delete一个对象

静态成员变量

普通成员变量每个对象有各自一份,而静态成员变量一共就一份,被所有对象共享;普通成员函数必须具体作用于某个对象,而静态成员函数并不具体作用于某个对象;静态成员不需要通过对象就能访问
sizeof运算符不会计算静态成员变量
静态成员变量本质上是全局变量,哪怕一个对象都不存在,类的静态成员变量也存在;同理,静态成员函数本质上也是全局函数;
注意:必须在定义类的文件中对静态成员变量进行一次声明or初始化,否则编译能通过,链接不能通过
在静态成员函数中,不能访问非静态成员变量,也不能调用非静态成员函数

常量成员函数

class Sample
{
public:
	int value;
	void GetValue() const;//常量成员函数
	void func(){};
	Sample()}{};
};
void Sample::GetValue() const
{
value = 0;//wrong
func();//wrong 常量成员函数上不能执行非常量成员函数
}

运算符重载

本质是函数重载;
等号运算符重载示例:

String & operator = (const String & s)
{
	if(this == &s)
		return *this;
	delete [] str;
	str = new char[strlen(s.str)+1];
	strcpy(str, s.str);
	return *this;
}

继承关系、复合关系

虚函数和多态

在类定义中,前面有virtual关键字的成员函数是虚函数;注意嗷,virtual关键字只用在类定义里的函数声明中,写函数体是不用写;构造函数和静态成员函数不能是虚函数

class base
{
	virtual int get();
};
int base::get(){};

虚函数可以多态,普通函数不可以

多态的表现形式:

  1. 派生类的指针可以赋给基类指针
  2. 通过基类指针调用基类和派生类中的同名虚函数时:若该指针指向一个基类的对象,那么被调用时基类的虚函数;若该指针指向一个派生类的对象,那么被调用的是派生类的虚函数
  3. 多态的关键在于通过基类指针或引用调用一个虚函数时,编译时不确定到底调用的是基类的还是派生类的函数,运行时才确定,这叫动态联编
  4. 在派生类中和积累中虚函数同名同参数表的函数,不加virtual也自动成为虚函数
  5. 每一个有虚函数的类(或有虚函数的类的派生类)都有一个虚函数表,该类的任何对象中都放着虚函数表的指针。虚函数表中列出了该类的虚函数地址。每个对象会多出来的4个字节就是用来放虚函数表的地址的
  6. 堕胎的函数调用语句被编译成一系列根据基类指针所指向的(或基类引用所指向的)对象中存放的虚函数表的地址,在虚函数表中查找虚函数地址,并调用虚函数的指令

输入输出和模板

输入输出流,文件读写(略略略)

函数模板和类模板

在有多个函数和函数模板名字相同的情况下,编译器处理一条函数调用语句的顺序:
1)先找参数完全匹配的普通函数(不是由模板实例化而得的函数)
2)再找参数完全匹配的模板函数
3)再找实参经过自动类型转换后能够匹配的普通函数
4)上面的都找不到,则报错

编译器由类模板生成类的过程叫类模板的实例化,由类模板实例化得到的类叫模板类
同一个类模板的两个模板类是不兼容的

模板标准库STL

  1. string类
    string类时模板类typedef basic_string<char> string
    使用string类要包含头文件
    初始化举例:
string s1("Hello");
string month = "March";
string s2(8,'x');//8个x

可以用“=”赋值,assign复制,compare比较,substr子串,sawp交换,find寻找,rfind倒找,erase删除,replace替换,insert插入,c_str转换成char*字符串

vector、deque、list
set、map、multiset、multimap
stack、queue、priority_queue

函数对象

若一个类重载了运算符“()”,则该类的对象就成为函数对象
在这里插入图片描述
在这里插入图片描述

  • 1
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值