类的默认成员函数
如果一个类中没有任何对象,并不意味着什么都没有,类里面还又默认的六个成员函数
构造函数
构造函数与类名是相同的,不需要用户主动调用当然也不能主动调用,创建对象时自动生成,这就是构造函数
1. #include <iostream>
1. u[sin](http://c.biancheng.net/ref/sin.html)g namespace std;
1.
1. class Student{
1. private:
1. char *m_name;
1. int m_age;
1. float m_score;
1. public:
1. //声明构造函数
1. Student(char *name, int age, float score);
1. //声明普通成员函数
1. void show();
1. };
1.
1. //定义构造函数
1. Student::Student(char *name, int age, float score){
1. m_name = name;
1. m_age = age;
1. m_score = score;
1. }
1. //定义普通成员函数
1. void Student::show(){
1. cout<<m_name<<"的年龄是"<<m_age<<",成绩是"<<m_score<<endl;
1. }
1.
1. int main(){
1. //创建对象时向构造函数传参
1. Student stu("小明", 15, 92.5f);
1. stu.show();
1. //创建对象时向构造函数传参
1. Student *pstu = new Student("李华", 16, 96);
1. pstu -> show();
1.
1. return 0;
1. }
定义了一个构造函数Student(char *, int, float),它的作用是给三个私有成员的值赋值,要想调用该构造函数,就要在创建对象的时候同时传递实参,并且实参有()包围,和普通的函数调用非常类似。 栈上面创建对象的时候实参位于对象名后面,例如Student stu("小明",15,92.5f),在堆上创建对象的时候,实参位于类名后面 构造函数的属性必须是公有的,否则创建对象的时候无法调用,其他情况虽然不会报错但是并没有意义。 构造函数没有返回值,因为没有变量接受返回值,没有return语句 构造函数也能重载。
析构函数
创建对象时系统会自动调用析构函数来做清理工作,比如释放分配的内存,关闭打开的文件,这就是析构函数 我们定义了一个 VLA 类来模拟变长数组,它使用一个构造函数为数组分配内存,这些内存在数组被销毁后不会自动释放,所以非常有必要再添加一个析构函数,专门用来释放已经分配的内存。请看下面的完整示例
1. #include <iostream>
1. u[sin](http://c.biancheng.net/ref/sin.html)g namespace std;
1.
1. class VLA{
1. public:
1. VLA(int len); //构造函数
1. ~VLA(); //析构函数
1. public:
1. void input(); //从控制台输入数组元素
1. void show(); //显示数组元素
1. private:
1. int *at(int i); //获取第i个元素的[指针](http://c.biancheng.net/c/80/)
1. private:
1. const int m_len; //数组长度
1. int *m_arr; //数组指针
1. int *m_p; //指向数组第i个元素的指针
1. };
1.
1. VLA::VLA(int len): m_len(len){ //使用初始化列表来给 m_len 赋值
1. if(len > 0){ m_arr = new int[len]; /*分配内存*/ }
1. else{ m_arr = NULL; }
1. }
1. VLA::~VLA(){
1. delete[] m_arr; //释放内存
1. }
1. void VLA::input(){
1. for(int i=0; m_p=at(i); i++){ cin>>*at(i); }
1. }
1. void VLA::show(){
1. for(int i=0; m_p=at(i); i++){
1. if(i == m_len - 1){ cout<<*at(i)<<endl; }
1. else{ cout<<*at(i)<<", "; }
1. }
1. }
1. int * VLA::at(int i){
1. if(!m_arr || i<0 || i>=m_len){ return NULL; }
1. else{ return m_arr + i; }
1. }
1.
1. int main(){
1. //创建一个有n个元素的数组(对象)
1. int n;
1. cout<<"Input array length: ";
1. cin>>n;
1. VLA *parr = new VLA(n);
1. //输入数组元素
1. cout<<"Input "<<n<<" numbers: ";
1. parr -> input();
1. //输出数组元素
1. cout<<"Elements: ";
1. parr -> show();
1. //删除数组(对象)
1. delete parr;
1.
1. return 0;
1. }
VLA就是VLA的析构函数,唯一作用就是删除释放后已经分配的内存, 析构函数用加类名来命名,本来~是不允许出现的但是这里是一个特例,目的是与构造函数加以区分 C++中new和delete分别用来分配和和释放内存,它们与C语言中malloc()和free不同,但是new会分配内存会调用构造函数,用delete时调用析构函数。
析构函数的执行时机
析构函数在对象被销毁后使用,而对象的销毁时机与它所在的内存区域有关 在所有函数之外创建的对象是全局对象,和全局变量类似,位于全局数据区,程序在结束执行时会调用这些对象的析构函数。 在函数内部创建的对象是局部对象,在函数调用完成后进行销毁,new 创建的对象位于堆区,通过 delete 删除时才会调用析构函数;如果没有 delete,析构函数就不会被执行。
拷贝构造函数
只有单个形式参数,该形参是本类类型对象的引用,用已经存在的类型对象创建新对象时由编译器自动调用
- 拷贝构造函数是构造函数的一个重载形式
- 拷贝构造函数的参数只有一个而且必须使用引用传参,使用传值传参会引发无穷递归调用
- 若未定义,那么系统会生成默认的拷贝构造函数