类的定义
class 类名{
//成员变量
//成员方法
}
C++实现的第一个小案例
通过这个案例我们可以了解到C++独有的特点,优点:方法和变量放在了一起,优化了代码的调用,如果在C语言中我们函数调用还要写上函数的返回类型,在C++中,类名就是返回类型,只需要,对象实例化后,就可以直接调用。
cpp
#include<iostream>
using namespace std;
class student {
//成员变量一般是私有
private:
int math_sorce;
int Chinese_sorce;
int English_sorce;
//方法一般是公有
public:
int add(int math, int Chinese, int English)
{
int add = math + Chinese + English;
return add;
}
};
int main()
{
//对象的实例化
student s1;
int sum=s1.add(89, 99, 60);
cout << sum << endl;
}
对象的实例化
类是对象进行⼀种抽象描述,是⼀个模型⼀样的东西,限定了类有哪些成员变量,这些成员变量只 是声明,没有分配空间,用类实例化出对象时,才会分配空间。所以一般要对对象进行实例化后才可以进行对成员方法的调用。
⼀个类可以实例化出多个对象,实例化出的对象占用实际的物理空间,存储类成员变量。
未实例化通过类域调用的错误案例
this指针
this指针是一个用来区分不同成员函数的调用,编译器编译后,类的成员函数默认都会在形参第⼀个位置,增加⼀个当前类类型的指针,叫做this 指针。
void Init(类名* const this, int year, int month, int day)
类的成员函数中访问成员变量,本质都是通过传递this指针访问的。
C++规定不能在实参和形参的位置显示的写this指针(编译时编译器会处理) ,但是可以在函数体内显示使用this指针。
this指针类型面试题
此题,可以传入的是一个空指针,成员变量前会有一个默认的this指针,此题传入的是一个空指针,对空指针中的变量进行解引用会造成程序崩溃。
访问限定符
访问限定符分为:public,protected和private这三个,public修饰的成员在类外可以直接被访问,protected和private修饰的成员在类外不能直接被访。⼀般成员变量都会被限制private/protected,需要给别⼈使⽤的成员函数会放为public。
访问权限作⽤域从该访问限定符出现的位置开始直到下⼀个访问限定符出现时为止,如果后⾯没有 访问限定符,作⽤域就到 }即类结束。
class定义成员没有被访问限定符修饰时默认为private ,在C++中struct可以升级类,在类中可以定义函数,struct默认为public。
类的默认成员函数
构造函数
构造函数是特殊的成员函数,需要注意的是,构造函数虽然名称叫构造,但是构造函数的主要任务并不是开空间创建对象,而是对象实例化时初始化对象。构造函数的本质是完成初始化工作。
构造函数的特点:
//无参构造
类名 ()
{
}
//有参构造
类名(参数类型 参数)
{
}
-
函数名与类名相同。
-
无返回值。
-
对象实例化时系统会自动调用对应的构造函数。
-
构造函数可以重载(一般可以提供一个全缺省的构造函数)。
-
如果类中没有显式定义构造函数,则C++编译器会⾃动⽣成⼀个⽆参的默认构造函数,⼀旦用户显式定义编译器将不再生成。
-
无参构造函数、全缺省构造函数、我们不写构造时编译器默认生成的构造函数,都叫做默认构造函 数。但是这三个函数有且只有⼀个存在,不能同时存在。
-
编译器默认生成的构造,对内置类型成员变量的初始化没有要求,也就是说是是否初始化是不确定的,看编译器。对于自定义类型成员变量,要求调用这个成员变量的默认构造函数初始化。
析构函数
析构函数与构造函数功能相反,析构函数不是完成对对象本身的销毁,C++规定对象在销毁时会自动调用析构函数,完成对象中资源的清理释放工作。
析构函数的特点
-
析构函数名是在类名前加上字符~。
-
无参数无返回值。
-
⼀个类只能有⼀个析构函数。若未显式定义,系统会⾃动⽣成默认的析构函数。
-
对象生命周期结束时,系统会自动调用析构函数。
-
跟构造函数类似,我们不写编译器自动生成的析构函数对内置类型成员不做处理,自定类型成员会调用他的析构函数。
-
还需要注意的是我们显示写析构函数,对于自定义类型成员也会调用他的析构,也就是说自定义类 型成员无论什么情况都会自动调用析构函数。
-
如果类中没有申请资源时,析构函数可以不写,直接使⽤编译器生成的默认析构函数。
-
⼀个局部域的多个对象,C++规定后定义的先析构。
总结:析构和构造类似与栈与队列中的函数的初始化和销毁。
拷贝构造
拷贝构造
cpp#include<iostream> using namespace std; class Date { public: Date(int year = 1, int month = 1, int day = 1) { _year = year; _month = month; _day = day; } Date(const Date& d) { _year = d._year; _month = d._month; _day = d._day; } private: int _year; int _month; int _day; }; int main() { Date d1(2024, 7, 5); //拷贝构造 Date d2(d1); Date d3=d1; }
⼀个构造函数的第⼀个参数是自身类类型的引⽤,且任何额外的参数都有默认值,则此构造函数 也叫做拷贝构造函数,也就是说拷贝构造是⼀个特殊的构造函数。使用同类对象初始化创建对象
拷贝构造的特点
-
拷贝构造函数是构造函数的⼀个重载。
-
拷贝构造函数的第⼀个参数必须是类类型对象的引用,拷贝构造函数也可以多个参数,但是第⼀个参数必须是类类型对象的引用,后面的参数必须有缺省值。
为什么必须是类类型对象的引用?
因为在c++编译器调用的时候,当进行传值传参时,传值传参是一种拷贝就会引发拷贝构造,这样就会引发无限递归调用的情况。当使用引用的时候就会取别名,不会引发拷贝构造。
传值调用时的循环现象
**注意:**权限访问问题,前面我们说过,传值传参返回值是一块临时对象,这里是只读,到拷贝构造里面变成读和写,访问权限被放大了,因此要记得加上const关键字。
- 若未显式定义拷贝构造,编译器会生成自动生成拷贝构造函数。自动生成的拷贝构造对内置类型成员变量会完成值拷贝/浅拷贝(⼀个字节⼀个字节的拷贝),对自定义类型成员变量会调⽤他的拷贝构造。
**深拷贝与浅拷贝的区别:**对于栈这中的值拷贝/浅拷贝都是不行的,因为里面涉及到了指针的指向和空间中的资源。
当我们不写拷贝构造的时候,会调用默认构造,但是我们要搞清楚,默认构造是值拷贝,值拷贝对于栈这种情况就是不满足,我们要自己写深拷贝。