从C到C++学习笔记

之前学习过C语言和Java语言,现在想了解一些C++的知识,这个笔记记录下C++与C的不同。小白水平,有错误的欢迎指正
~课程来自B站:两小时从c到c++

1.C++的头文件不必是.h结尾

2.名字空间namespace
为防止名字冲突(程序里出现同名变量),c++引入名字空间,用::运算符限定某个名字属于哪个空间
使用的具体方法:
1)using namespace X; //引入整个名字空间
2)using X::name ; //使用单个名字
3)X::name; //程序中加上名字空间前缀,如X::

3.C++的(头文件iostream)将输入输出看成一个流,并用输出运算符 << 和输入运算符 >> 对数据(变量和常量)进行输入输出;
其中有cout和cin分别代表标准输出流对象(屏幕窗口)和标准输入流对象(键盘);标准库中的名字都属于标准名字空间std

4.变量“即用即定义”,且可用表达式初始化
不用和c语言一样把函数的变量都放在一起

5.{ }内部作用域
程序块{ }内部作用域可定义域外部作用域同名的变量,在该块里就隐藏了外部变量。{ }块内外的同名变量不会相互影响。

6.局部变量
for循环语句可以定义局部变量,比如循环用的i,j等变量。作用域就在当前的for循环里面。

7.同名全局变量的访问
访问和内部作用域变量同名的全局变量,要用全局作用域限定 ::(比如::a,表示访问全局变量a)

8.引用类型,即一个变量是另一个变量的别名。
举例:double a = 3.1415927; double &b = a;
引用经常用作函数的形参,表示形参和实参实际上是同一个对象,在函数中对形参的修改也就是对实参的修改。
当实参占据内存大时,用引用代替传值(需要复制)可提高效率。如果不希望因此无意中修改实参,可以用const修改符。

//x,y是实参的引用
void swap(int &x, int &y) {
cout << "swap函数内交换前:" << x << " " << y << endl;
int t = x; x = y; y = t;
cout << "swap函数内交换后:" << x << " " << y << endl;
}
int main(){
int a = 3, b = 4;
swap(a, b); //x,y将分别是a,b的引用,即x就是a,y就是b
cout << a << ", " << b << endl; // Displays 100, 4.
return 0;
}

9.内联函数
对于不包含循环的简单函数,建议用inline关键字声明 为"inline内联函数"。(不当作函数调用而是直接替换代码)
编译器将内联函数调用用其代码展开,称为“内联展开”,避免函数调用开销,提高程序执行效率

10.try-catch语句
通过 try-catch处理异常情况
正常代码放在try块,catch中捕获try块抛出的异常

11.默认形参
函数的形参可带有默认值,必须一律在最右边。
错误示范

/*错: 默认参数一律靠右*/
double test(double a, double b = 7, int c) {
return a - b;
}

12.函数重载
C++允许函数同名,只要它们的形参不一样(个数或对应参数类型),调用函数时将根据实参和形参的匹配选择最佳函数,
如果有多个难以区分的最佳函数,则变化一起报错!
注意:不能根据返回类型区分同名函数,相同的形参,不同的返回类型不能被区分。

  1. 运算符重载
    重新对一个运算符号的操作根据需要进行定义。
struct Vector2{
 double x;
 double y;
};
Vector2 operator+ (Vector2 a, Vector2 b) {
Vector2 r;
r.x = a.x + b.x;
r.y = a.y + b.y;
return r;
}

13.模板template函数
使用模板函数,使某个使用时不再收到参数类型的限制,比如数学运算时,运算类型可能是整型、浮点型。

//可以对任何能比较大小(<)的类型使用该模板让编译器
//自动生成一个针对该数据类型的具体函数
template<class T1, class T2>
T1 minValue(T1 a, T2 b) {//return a<b?a:b
if (a < b) return a;
else return (T1)b; //强制转化为T1类型
}

14.动态内存分配
关键字 new 和 delete 比C语言的malloc/alloc/realloc和free更好,可以对类对象调用初始化构造函数或销毁析构函数
new 分配的是堆存储空间,即所有程序共同拥有的自由内存空间,普通的局部变量是这个程序自身的静态存储空间;
new一个新对象时会对构造函数做初始化,比如初始化为0;
new分配连续空间时返回的是这块连续空间的起始地址;
申请多少空间就要释放多少空间,不然会造成内存泄漏;

15.类(C的struct类型上,增加了“成员函数”)
C的strcut可将一个概念或实体的所有属性组合在一起,描述同一类对象的共同属性,
C++使得struct不但包含数据,还包含函数(方法)用于访问或修改类变量(对象)的这些属性。
举例:使用自引用类型实现连续调用

// 成员函数 返回 “自引用” (*this)
#include <iostream>
using namespace std;
struct Date {
int d, m, y;
void init(int dd, int mm, int yy) {
d = dd; m = mm; y = yy;
	}
void print() {
cout << y << "-" << m << "-" << d << endl;
	}
Date& add(int dd) {
d = d + dd;
return *this; //this是指向调用这个函数的类型对象指针,
// *this就是调用这个函数的那个对象
//这个成员函数返回的是“自引用”,即调用这个函数的对象本身
//通过返回自引用,可以连续调用这个函数
 // day.add(3);
 // day.add(3).add(7);
				}
};

16.构造函数和析构函数
构造函数是和类名同名且没有返回类型的函数,在定义对象时会自动被调用,而不需要在单独调用专门的初始化函数如init,构造函数用于初始化类对象成员,包括申请一些资源,如分配内存、打开某文件等

析构函数是在类对象销毁时被自动调用,用于释放该对象占用的资源,如释放占用的内存、关闭打开的文件

struct Date {
int d, m, y;
Date(int dd, int mm, int yy) {
d = dd; m = mm; y = yy;
cout << "构造函数" << endl;
}  //使用构造函数时要传入三个参数才可以的,这里可以使用默认参数
void print() {
cout << y << "-" << m << "-" << d << endl;
}Date() {//析构函数名是~和类名,且不带参数,没有返回类型
//目前不需要做任何释放工作,因为构造函数没申请资源
cout << "析构函数" << endl;
}
};

析构函数举例

struct student {
char *name;
int age;
student(char *n = "no name", int a = 0) {
name = new char[100]; // 比malloc好!
strcpy(name, n);
age = a;
cout << "构造函数,申请了100个char元素的动态空间" << endl;
}
virtual ~student(){ // 析构函数
delete name; // 不能用free!
cout << "析构函数,释放了100个char元素的动态空间" << endl;
}
};

为什么要用虚析构函数(待学习):
这样做是为了当用一个基类的指针删除一个派生类的对象时,派生类的析构函数会被调用。
如果一个类要被使用成多态(polymorphic)的,那么这个virtual是必须的。

  1. 访问控制、类接口(待深入学习)
    将关键字struct换成class
class student {
char *name;
int age;
student(char *n = "no name", int a = 0) {
name = new char[100]; // 比malloc好!
strcpy(name, n);
age = a;
cout << "构造函数,申请了100个char元素的动态空间" << endl;
}
virtual ~student() { // 析构函数
delete name; // 不能用free!
cout << "析构函数,释放了100个char元素的动态空间" << endl;
}
};

class定义的类的成员默认都是私有的private。
接口:public的公开成员(一般是成员函数)称为这个类的对外接口,外部函数只能通过这些接口访问类对象,private等非public的包含内部内部细节,不对外公开,从而可以封装保护类对象!

18.拷贝(待深入学习)
拷贝构造函数:定义一个类对象时用同类型的另外对象初始化
赋值运算符:一个对象赋值给另外一个对象,默认的“拷贝构造函数”是“硬拷贝”或“逐成员拷贝”。

19.类模板
可以将一个类变成“类模板”或“模板类”,正如一个模板函数一样。

template<class T>
class Array {
T size;
T *data;
public:
Array(int s) {
size = s;
data = new T[s];
}
virtual ~Array() {
delete[] data;
}
T &operator [] (int i) {
if (i < 0 || i >= size) {
cerr << endl << "Out of bounds" << endl;
throw "index out of range";
}
else return data[i];
}
};

20.类型别名
给默认的数据类型重新起一个名字

#include <iostream>
using namespace std;
typedef int INT;
int main() {
INT i = 3; //等价于int i = 3;
cout << i << endl;
return 0;
}

21.继承(待深入学习)
一个派生类(derived class)从1个或多个父类(parent class) / 基类(base class)继承,即继承父类的属性和行为,但也有自己的特有属性和行为。
派生类的构造函数只能描述它自己的成员和其直接基类的初始式,不能去初始化基类的成员。

22.虚函数Virtual Functions(待深入学习)
派生类的指针可以自动转化为基类指针。
可以从多个不同的类派生出一个类来:多重派生(Multiple inheritance)

23.纯虚函数(pure virtual function )和抽象类(abstract base class)
函数体=0的虚函数称为“纯虚函数”。包含纯虚函数的类称为“抽象类”
从抽象类派生的类型如果没有继承实现所有的纯虚函数,则仍然是“抽象类

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值