C++笔记(11-20)条
文章目录
十一、空指针&野指针:指针都占8字节32位
1、空指针:没有存储任何内存地址的指针变量。
如:int* p = NULL;
2、野指针:存储有一个内存地址,但此内存地址指向的空间可能不存在,或没有访问权限。
如随便设置一个地址:int* p = (int*)0x1234;
访问空指针和野指针的*p是会出现问题的。
十二、常量指针(常量的指针 *p)&指针常量(指针是常量 p)
1.常量指针(常量的指针),其中*p 是常量,不可修改
如下:const 修饰 (* p)(常量)
int a = 20;
int b = 30;
const int* p = &a; // *p = 90,这样的操作是不可以修改的
cout << *p << endl;
a = 90; // *p = 90不行,但直接改int a可以
cout << *p << endl;
p = &b; // *p不能修改,但p可以修改,即可以重新指向其他变量的地址
cout << *p << endl;
总结:在const int* p = &a中,
①*p不可修改
②a可以修改,*p跟着被修改
③p可以修改,即指向其他地址
补充:
const int a = 20;
int p = &a; //INVALID
const int p = &a; //VALID
C++禁止将const 地址赋给非const 的指针。如果非要这样做,可以通过const_cast 强制转换。
2.指针常量(指针是常量),其中 p是常量,不能修改
如下:const 修饰( p)(指针)
int a = 10;
int b = 20;
int* const p = &a; // p = &b ,这样的操作不行,因为p是常量
cout << p << " , "<< * p << endl;
a = 90; // a = 90 等效于 *P = 90
cout << a<< " , " << *p << endl;
总结:在int* const p = &a; 中
①p不可以修改,即不能指向其他地址
②*p可以修改,a跟着被修改
③a可以修改,*p跟着被修改
十三、引用:取别名,本质是指针常量
一、基本语法:type& newname = oldname
int a = b; // 将 b 的值copy给 a, a、b不同地址
int& b = a; // 给a取了个别名b,a和b 指向同一个地址
二、引用在函数中的运用:
int function(int& a, int& b)
如上,可以在函数体中,通过修改形参的值更改实参的值。
三、常量引用(常引用)
void function( const int& a):const 修饰 & a,a 是常量
防止修改形参的值更改了实参的值
如:
int b = 10;
function(b) // a和b是同一个变量,只是在函数中,无法修改b,也就是无法修改a
十四、数组
一、当数组作为实参传递时,传递的只是首元素的地址,所以还要传递数组的长度。
二、数组遍历
①下标遍历
int arr[10] = {0};
int len = sizeof(arr) / sizeof(int);
for (int i = 0 ; i < len ; i ++ ){}
②元素迭代
for (int tmp : arr){}
// 无法通过修改tmp的值来修改arr的值
十五、new & delete
参考:
https://blog.youkuaiyun.com/weixin_70273825/article/details/134327992
int arr1[11] = { 0,1,2,3,4,5,6,7,8,9 };
cout << arr1 << endl; // arr1 就是首地址,首地址[i] 就是数组元素
int* pint = new int(6);
cout << *pint << endl;
int* p = new int[10] {48, 4, 5, 67, 899, 333}; // 遍历数组p,不能用元素迭代
for (int i = 0; i < 10; i++) {
cout << p[i] << " ";
}
cout << endl;
delete pint;
delete[]p;
1.new
2.delete
3.new[]
4.[]delete
十六、面向对象与面向过程的区别
-
面向过程:亲力亲为
面向过程是一种以事件为中心的编程思想,编程的时候把解决问题的步骤分析出来,然后用函数把这些步骤实现,在一步一步的具体步骤中再按顺序调用函数。 -
面向对象:术业有专攻
面向对象是一种以“对象”为中心的编程思想,把要解决的问题分解成各个对象,建立对象的目的不是为了完成一个步骤,而是为了描叙某个对象在整个解决问题的步骤中的属性和行为。
十七、三种对类成员的访问权限
在C++中,权限通常指的是对类成员的访问权限。C++有三种访问权限:
public:公共权限,表示在类外部可以直接访问。
protected:受保护的权限,类外无法访问,表示只能由当前类及其派生类(子类)访问。
private:私有权限,表示只能由类内部访问,不能被类外部访问。
默认情况下,如果不指定访问权限,C++会将成员声明为private。
十八、静态static(共用)
一、类的静态成员
(1)在类中用static修饰成员,则该成员是静态成员;
(2)静态成员是属于类本身的,所有类的对象共享;
(3)类的对象都可以访问静态成员,但是所有类的成员访问的静态成员都是同一份静态成员;(一变全变)
(4)静态成员在类内部声明时加static声明,在类外定义静态成员时无需添加static修饰;
二、静态成员初始化
①一般是类内定义,类外进行初始化赋值
②如果是静态常量,且数据类型是整型(int,short,long,long long,char,bool),允许在定义时就初始化赋值,也可以类外赋值。
三、访问静态成员
①使用类来访问
②使用对象来访问
class MyClass {
public:
static int count; //类内定义
const static int score = 99; //静态常量在定义时就初始化赋值
MyClass() { // 构造函数
count++;
}
};
int MyClass::count = 0; // 类外进行初始化赋值
int main() {
MyClass obj1;
cout << MyClass::score << endl; // 使用类来访问
cout << MyClass::count << endl; //使用类来访问
cout << obj1.count << endl; // 使用对象来访问
obj1.count = 78; //MyClass 类的count都为78
return 0;
}
十九、构造函数,要public权限
一、构造函数的作用:初始化对象的数据成员
二、定义:以类名作为函数名,无返回类型,可以重载
三、构造函数的分类:
①无参构造函数,自己不写,函数默认自动生成
②一般构造函数,可以有多个,创建对象时根据传入的参数不同调用不同的构造函数,可以配合列表初始化
③复制构造函数(拷贝构造函数)
四、构造函数的调用
①显式调用
Coordinate c1 = Coordinate();
Coordinate c2 = Coordinate(1.2, 3.2);
等效如下:
Coordinate c1;
Coordinate c2(1.2, 3.2);
②隐式调用:单个参数也可以不需要{}
Coordinate c1 = {};
Coordinate c2 = { 1.2, 3.2 };
五、explicit
explicit关键字在C++中是用来修饰类的构造函数的,它的目的是用来防止不应允许的类型转换,杜绝隐式调用。
代码示例:
class Coordinate
{
public:
//无参构造函数,杜绝隐式调用
explicit Coordinate()
{
c_x = 0;
c_y = 0;
}
// 一般构造函数 + 列表初始化
Coordinate(double x, double y) :c_x(x), c_y(y) {}
//拷贝构造函数
Coordinate(const Coordinate& c)
{
// 复制对象c中的数据成员
c_x = c.c_x;
c_y = c.c_y;
}
}
二十、析构函数
一、作用:析构函数完成的是对象中资源的清理工作。通常是对对象中动态开辟的空间进行清理。
二、析构函数特性:
1.析构函数的函数名是 ~类名
2.析构函数无参数无返回值
3.一个类中只能有一个析构函数,析构函数不支持重载
4.若未显式定义析构函数,编译器会默认生成一个析构函数
5.析构函数由编译器在[对象生命周期]结束时自动调用
代码示例: