一.C++究竟为我们提供了哪些默认的成员函数
成员函数 | 作用 |
---|---|
构造函数 | 初始化对象成员(不是开辟空间,开辟空间是new) |
析构函数 | 编译器销毁对象,然后自动调用析构函数清理资源 |
拷贝构造函数 | 已存在的对象初始化新对对象时调用 |
运算符重载 | 已存在对象赋值已存在对象时调用 |
取地址重载 | 不常重载 |
const取地址重载 | 不常重载 |
二.关于默认成员函数的几点规则
-
构造函数
- 构造函数可以重载,没有重载的话就使用默认的无参构造函数,重载的话就不生成默认构造函数;
- 全是省略值得构造函数等于无参构造函数例如
Student() 等于 Student(int age=18 , int number=100)
; - 构造函数会初始化非内置类型的成员对象,而C++不保证初始化内置类型的成员对象;
-
析构函数
-
析构函数不可以重载;
-
析构函数不是用来销毁对象的,而是在编译器销毁对象的时候自动调用析构函数来清理资源的;
-
作为基类的时候析构函数加virtual关键字,子类才能够销毁对象时释放资源;
-
不涉及资源的释放可以不写;
-
-
拷贝构造函数
-
使用已存在的对象来初始化新的对象;
-
内置类型拷贝方式:浅拷贝,即按位拷贝,所以成员存在指针或者引用的时候会出现两个对象指向同一个地址问题,需要查看深拷贝相关知识;
-
自定义类型拷贝:例如sstd:;tring,调用std::string自己的拷贝构造函数;
-
拷贝构造函数是构造函数的一个重载形式;
-
拷贝构造函数的参数必须是引用,否则会无限递归(值传递的话实参给形参赋值调用拷贝构造,形参自己又给自己赋值又调用拷贝构造,使用引用的话就是内置类型,使用赋值方式而不是拷贝构造);
-
拷贝构造函数调用时机
-
一个已存在的对象初始化新对象
MyClass obj1; MyClass obj2(obj1); // 调用拷贝构造函数
-
通过值传递方式传递对象给函数:当将对象作为参数传递给函数时,如果参数是按值传递的,拷贝构造函数会被调用来创建该参数的副本。例如:
void foo(MyClass obj); // 按值传递对象 MyClass obj1; foo(obj1); // 调用拷贝构造函数
-
在函数中返回对象时:当函数返回一个对象时,拷贝构造函数被调用来创建返回值的副本。例如:
MyClass bar() { MyClass obj; return obj; // 调用拷贝构造函数 }
-
初始化一个对象数组:当使用一个已存在的对象来初始化对象数组时,拷贝构造函数会被调用。例如:
MyClass arr[5] = {obj1, obj2, obj3}; // 调用拷贝构造函数
-
-
-
运算符重载(=)
-
把一个对象的值赋值给另一个对象的时候使用;
-
重载后 ‘=‘ 就可以用于两个对象之间的赋值了;
-
内置类型还是按照位赋值;
-
赋值运算符重载调用时机
-
对象赋值给另一个对象:当使用一个对象将其值赋给另一个对象时,赋值运算符重载函数被调用。例如:
MyClass obj1; MyClass obj2; obj2 = obj1; // 调用赋值运算符重载函数
-
自我赋值:当一个对象将自身赋值给自身时,赋值运算符重载函数被调用。例如:
MyClass obj; obj = obj; // 自我赋值,调用赋值运算符重载函数
-
初始化时使用赋值运算符:当对象进行初始化时使用赋值运算符进行赋值,赋值运算符重载函数被调用。例如:
MyClass obj1; MyClass obj2 = obj1; // 调用赋值运算符重载函数
-
-
-
取地址重载和const取地址重载:一般不单独考虑
三.几种默认成员函数的使用示例
class Studeng()
{
private:
int _age;
int _number;
std::string _name;
public:
//默认构造函数
Student(){}
//都是缺省值的参数等同于默认构造函数
Student(int age = 18,int number = 2023,std::string name = "Tom"){}
//重载默认构造函数
Student(int age,int number,std::string name)
{
_age=age;
_number=number;
_name=name;
}
//拷贝构造函数,重载于构造函数
Student(const Student& StuName){}
//析构函数:不可以重载
~Student(){}
//赋值运算符重载
Student& operator=(const Student& StuName){}
//取地址和const取地址重载,这里不做使用演示
Student* operator&()
{
return this;
}
const Student* operator&()const
{
return this;
}
}
int main()
{
//使用重载的带参构造函数初始化对象Tom 和 Jack
Student Tom(18,001,"Tom");
Student Jack(18,002,"Jack");
//使用拷贝构造函数初始化新对象Tony
Student Tony(Tom);
//使用重载运算符赋值已存在对象Jack
Jack=Tom
}
四.关于三中几段代码的具体说明
int main()
{
//使用重载的带参构造函数初始化对象Tom 和 Jack
Student Tom(18,001,"Tom");
因为Student有三个成员变量_age,_number,std::string _name故此处直接调用的重载的带参的构造函数初始化了Tom这个对象的这三个成员变量
具体来讲,_ge 和 _number 是内置类型的int型的,直接按照位赋值初始化,std::string是用户自定义类型的,所以使用std::string的构造函数初始化
Student Jack(18,002,"Jack");
同上
//使用拷贝构造函数初始化新对象Tony
Student Tony(Tom);
使用Tony的拷贝构造函数,把Tom对应的数据复制过来,但是对于指针和引用直接拿过来就会有问题,参照深拷贝
//使用重载运算符赋值已存在对象Jack
Jack=Tom
对象之间是不能像基本类型一样直接使用 "="的,所以需要进行重载
}