1 类的默认6个成员函数
如果定义了一个空类,其实不是空类,任何一个类都会有默认成员函数。
自己定义了就用定义,不定义就用默认生成的。
-
初始化 和 清理
构造函数:完成初始化工作
析构函数:完成清理工作 -
赋值 和 拷贝
拷贝构造函数:使用同类对象初始化创建对象
运算符重载:一个对象与另一对象进行运算 -
取地址重载
普通对象
const对象
1.1 构造函数
构造函数是特殊函数,实例化时,在生成相应对象时编译器会自动调用该函数,保证每个对象都有一个合适的初始化值,并且在对象生命周期里面只能调用一次。
构造函数的基本特征:
- 函数名 与 类名 同名
- 无返回值
- 对象实例化时自动调用对应构造函数
- 构造函数可以重载
#include <cstring>
#include <iostream> //头文件,C++11可以不用加.h、*hxx
using namespace std; //命名空间声明
class Studet
{
public: //共有的
Studet(const char *name, int age); //构造函数
void SetStudetInfo(const char *name, int age); //方法
void ShowStudetInfo(void);
private: //私有的
char Name[20]; //属性
int Age; //属性
};
Studet::Studet(const char *name, int age) //构造函数
{
std::cout << "调用了构造函数" << std::endl;
strcpy(Name, name);
Age = age;
}
void Studet::SetStudetInfo(const char *name, int age) //方法
{
strcpy(Name, name);
Age = age;
}
void Studet::ShowStudetInfo(void)
{
std::cout << Name << " " << Age << std::endl;
}
int main(void)
{
Studet s1("王二", 21);
//s1.SetStudetInfo("李三", 20);
s1.ShowStudetInfo();
return 0;
}
构造函数 重载
#include <cstring>
#include <iostream> //头文件,C++11可以不用加.h、*hxx
using namespace std; //命名空间声明
class Studet
{
public: //共有的
Studet(const char *name, int age); //构造函数
Studet(void); //构造函数 重载
void SetStudetInfo(const char *name, int age); //方法
void ShowStudetInfo(void);
private: //私有的
char Name[20]; //属性
int Age; //属性
};
Studet::Studet(const char *name, int age) //构造函数
{
std::cout << "调用了构造函数" << std::endl;
strcpy(Name, name);
Age = age;
}
Studet::Studet(void) //构造函数 重载
{
std::cout << "调用了构造函数" << std::endl;
strcpy(Name, "小白");
Age = 18;
}
void Studet::SetStudetInfo(const char *name, int age) //方法
{
strcpy(Name, name);
Age = age;
}
void Studet::ShowStudetInfo(void)
{
std::cout << Name << " " << Age << std::endl;
}
int main(void)
{
Studet s1("王二", 21), s2;
//s1.SetStudetInfo("李三", 20);
s1.ShowStudetInfo();
s2.ShowStudetInfo();
return 0;
}
==重载构造函数 与 构造函数 合并 ==
#include <cstring>
#include <iostream> //头文件,C++11可以不用加.h、*hxx
using namespace std; //命名空间声明
class Studet
{
public: //共有的
Studet(const char *name, int age); //构造函数
void SetStudetInfo(const char *name, int age); //方法
void ShowStudetInfo(void);
private: //私有的
char Name[20]; //属性
int Age; //属性
};
Studet::Studet(const char *name = "小白", int age = 18) //缺省构造函数
{
std::cout << "调用了构造函数" << std::endl;
strcpy(Name, name);
Age = age;
}
void Studet::SetStudetInfo(const char *name, int age) //方法
{
strcpy(Name, name);
Age = age;
}
void Studet::ShowStudetInfo(void)
{
std::cout << Name << " " << Age << std::endl;
}
int main(void)
{
Studet s1("王二", 21), s2;
//s1.SetStudetInfo("李三", 20);
s1.ShowStudetInfo();
s2.ShowStudetInfo();
return 0;
}
==若不定义构造函数则是随机值,但对定义类型会初始化构造函数 ==
#include <cstring>
#include <iostream> //头文件,C++11可以不用加.h、*hxx
using namespace std; //命名空间声明
class Time
{
public: //共有的
Time(const char *name, int age) //构造函数
{
std::cout << "调用了Time构造函数" << std::endl;
Year = 2022;
Month = 10;
}
private: //私有的
int Year; //属性
int Month; //属性
};
class Studet
{
public: //共有的
void SetStudetInfo(const char *name, int age); //方法
void ShowStudetInfo(void);
private: //私有的
char Name[20]; //属性
int Age; //属性
Time Tm;
};
1.1.1 构造函数的初始化列表
- 构造函数的初始化列表是真的初始化,在定义的时候初始化。
#include <cstring>
#include <iostream> //头文件,C++11可以不用加.h、*hxx
using namespace std; //命名空间声明
class Studet
{
public: //共有的
Studet(char *name, int age); //构造函数
void SetStudetInfo(char *name, int age); //方法
void ShowStudetInfo(void);
private: //私有的
char* Name; //属性
int Age; //属性
};
//采用初始化列表
Studet::Studet(char* name, int age): Name(name), Age(age)
{
}
void Studet::ShowStudetInfo(void)
{
std::cout << Name << " " << Age << std::endl;
}
int main(void)
{
Studet s1("王二", 21);
s1.ShowStudetInfo();
return 0;
}
注意
- const 必需在初始化列表中初始化
- 引用必须初始化
1.2 析构函数
析构函数与构造函数相反,是用来清理对象。对象销毁时调用一次析构函数进行清理工作。
构造函数的基本特征:
- 析函数名 是在 类名 前加~
- 无返回值
- 一个类有且只有一个析构函数,如果没有显示定义,系统会自动生成默认的析构函数
- 对象声明结束时,编译器会自动调用析构函数
#include <cstring>
#include <iostream> //头文件,C++11可以不用加.h、*hxx
using namespace std; //命名空间声明
class Studet
{
public: //共有的
Studet(const char *name, int age); //构造函数
~Studet() //析构函数
{
std::cout << "调用了析构函数" << std::endl;
}
void SetStudetInfo(const char *name, int age); //方法
void ShowStudetInfo(void);
private: //私有的
char Name[20]; //属性
int Age; //属性
};
Studet::Studet(const char *name = "小白", int age = 18) //缺省构造函数
{
std::cout << "调用了构造函数" << std::endl;
strcpy(Name, name);
Age = age;
}
void Studet::SetStudetInfo(const char *name, int age) //方法
{
strcpy(Name, name);
Age = age;
}
void Studet::ShowStudetInfo(void)
{
std::cout << Name << " " << Age << std::endl;
}
int main(void)
{
Studet s1("王二", 21), s2;
//s1.SetStudetInfo("李三", 20);
s1.ShowStudetInfo();
s2.ShowStudetInfo();
return 0;
}
1.3 拷贝构造函数
拷贝 + 构造函数,看名字就是知道意思了。
**拷贝构造函数用于创建对象时,创建一个与一个对象一模一样的新对象。**
拷贝构造函数的基本特征:
- 拷贝构造函数是构造函数的一个重载形式
- 拷贝构造函数只有一个,且必须使用引用传参,如果使用传值的方式传参,将会引起无穷递归调用。
#include <cstring>
#include <iostream> //头文件,C++11可以不用加.h、*hxx
using namespace std; //命名空间声明
class Studet
{
public: //共有的
Studet(const char *name, int age); //构造函数
Studet(Studet &s); //构造函数
void SetStudetInfo(const char *name, int age); //方法
void ShowStudetInfo(void);
private: //私有的
char Name[20]; //属性
int Age; //属性
};
Studet::Studet(const char *name, int age) //构造函数
{
std::cout << "调用了构造函数" << std::endl;
strcpy(Name, name);
Age = age;
}
Studet::Studet(Studet &s) //拷贝构造函数
{
std::cout << "调用了拷贝构造函数" << std::endl;
strcpy(Name, s.Name);
Age = s.Age;
}
void Studet::SetStudetInfo(const char *name, int age) //方法
{
strcpy(Name, name);
Age = age;
}
void Studet::ShowStudetInfo(void)
{
std::cout << Name << " " << Age << std::endl;
}
int main(void)
{
Studet s1("王二", 21);
Studet s2(s1);
s1.ShowStudetInfo();
s2.ShowStudetInfo();
return 0;
}
注意
- 只进行字节拷贝的叫浅拷贝。自己不创建拷贝构造函数,则调用默认生成拷贝构造函数也能实现。
- 带指针(栈)的拷贝叫深拷贝。若用默认拷贝构造函数会出问题。
1.4 运算符重载
- 函数名:==operator== 接【需要重载的运算符符号】
- 函数原型为:【返回值类型】【operator】【操作符】【参数列表】
特别注意:
- 连接符 必须是 已有的,不能自己去创造新的操作。
- 重载操作符对的是自己定义类型。
- 作为类成员的重载函数时,其形参看起来比操作数目少 1 个成员,因为一个默认的this指针
- .*, ::, sizeof, ?:, ., 这五个运算符号不能重载。
1.4.1 相等运算符重载
#include <cstring>
#include <iostream> //头文件,C++11可以不用加.h、*hxx
using namespace std; //命名空间声明
class Studet
{
public: //共有的
Studet(const char *name, int age); //构造函数
Studet(Studet &s); //构造函数
bool operator == (Studet &s); //运算符重载函数
void SetStudetInfo(const char *name, int age); //方法
void ShowStudetInfo(void);
private: //私有的
char Name[20]; //属性
int Age; //属性
};
Studet::Studet(const char *name, int age) //构造函数
{
std::cout << "调用了构造函数" << std::endl;
strcpy(Name, name);
Age = age;
}
Studet::Studet(Studet &s) //拷贝构造函数
{
std::cout << "调用了拷贝构造函数" << std::endl;
strcpy(Name, s.Name);
Age = s.Age;
}
bool Studet::operator == (Studet &s) //运算符重载函数
{
return Age == s.Age;
}
void Studet::SetStudetInfo(const char *name, int age) //方法
{
strcpy(Name, name);
Age = age;
}
void Studet::ShowStudetInfo(void)
{
std::cout << Name << " " << Age << std::endl;
}
int main(void)
{
Studet s1("王二", 21);
Studet s2(s1);
s1.ShowStudetInfo();
s2.ShowStudetInfo();
if(s1 == s1)
{
std::cout << "调用了运算符重载函数" << std::endl;
}
return 0;
}
1.4.2 赋值运算符重载
#include <cstring>
#include <iostream> //头文件,C++11可以不用加.h、*hxx
using namespace std; //命名空间声明
class Studet
{
public: //共有的
Studet(const char *name, int age); //构造函数
Studet(Studet &s); //构造函数
Studet& operator = (Studet &s); //赋值运算符重载函数
void SetStudetInfo(const char *name, int age); //方法
void ShowStudetInfo(void);
private: //私有的
char Name[20]; //属性
int Age; //属性
};
Studet::Studet(const char *name, int age) //构造函数
{
std::cout << "调用了构造函数" << std::endl;
strcpy(Name, name);
Age = age;
}
Studet::Studet(Studet &s) //拷贝构造函数
{
std::cout << "调用了拷贝构造函数" << std::endl;
strcpy(Name, s.Name);
Age = s.Age;
}
Studet& Studet::operator = (Studet &s) //赋值运算符重载函数
{
strcpy(Name, s.Name);
Age = s.Age;
return *this;
}
void Studet::SetStudetInfo(const char *name, int age) //方法
{
strcpy(Name, name);
Age = age;
}
void Studet::ShowStudetInfo(void)
{
std::cout << Name << " " << Age << std::endl;
}
int main(void)
{
Studet s1("王二", 21);
Studet s2("李三", 20);
s1.ShowStudetInfo();
s2.ShowStudetInfo();
s2 = s1;
s2.ShowStudetInfo();
return 0;
}
注意: 赋值运算符重载函数类似拷贝构造函数,同样存在浅拷贝与深拷贝问题