C++(二十六) — 构造函数、析构函数、对象数组、复制构造函数

1、构造函数

(1)每个类都要定义它自己的构造函数和析构函数,是类的成员函数。

  特点:名称与类名相同;没有返回值;一定是共有函数,可以直接访问类内所有成员函数;可以带默认形参,可以重载;

class clock
{
public:
    // 无参构造函数
    clock()
    {
        cout << "无参构造函数" << endl;
    }
    // 有参构造函数
    clock(int h, int m , int s)
    {
        hour = h;
        minute = m;
        second = s;
        cout << "有参构造函数" << endl;
    }
    //// 有默认参数值的有参构造函数
    //clock(int h=8, int m=20, int s=20)
    //{
    //    hour = h;
    //    minute = m;
    //    second = s;
    //    cout << "有默认参数值的有参构造函数" << endl;
    //}
    //拷贝构造函数完成,用一个对象初始化另一个对象
    clock(const clock &t) // const 加不加都可以
    {
        cout << "复制构造函数" << endl;
    }

private:
    int hour; int minute; int second;
};

void main()
{
    clock myclock;  // 调用无参构造函数,不能加括号
    //clock myclock_1();// 调用有参构造函数,此时会出错,因为没有传参数
    clock myclock_2(8,20,20);// 有参构造函数,必须要写上参数

    clock myclock_3(myclock_2);// 调用复制构造函数
  clock myclock_3 = myclock_2;// 同样调用copy构造函数
system("pause"); }

(2)注意:

  (1)类中没有定义任何构造函数时,才使用默认构造函数,只要定义了,就不会存在默认构造函数;

  (2)不能同时出现无参构造函数和带有全部默认参数值的构造函数;二者只能出现一个;

  (3)复制构造函数,使用一个已存在的对象,初始化一个新的同类对象。如果未定义,系统将会自动生成;但是,如果申请动态空间(堆空间),则必须定义。

  (4)构造函数中调用构造函数,是危险的行为。(会因为调用匿名对象,而直接析构掉)

 2、对象数组

  解释为什么需要构造函数,在定义对象数组时,自动初始化。

class student
{
public:
    student(int, char*);
    student();
    ~student();
    void set(int i, char* c);
    void printstu()
    {
        cout << "id: " << id << "   name: " << name << setw(5) << endl;
    }
private:
    int id;
    string name;
};
student::student()
{
    cout << "默认无参构造函数" << endl;
}
student::student(int i, char* c)
{
    id = i;
    name = c;
    cout << "有参构造函数" << endl;
}
student::~student()
{
    cout << "析构函数" << endl;
}

void student::set(int i, char* c)
{
    id = i;
    name = c;
}

void main()
{
    // 对象数组
    student stu[5] = {
        student(1,"li"),
        student(2,"wang")
    };
    stu[2].set(3, "zhao");
    system("pause");
}

  定义两个构造函数,此时定义对象数组时,可以不用初始化。

  构造函数在定义对象时调用,析构函数在程序结束时调用,而且,析构顺序与构造顺序相反。

3、复制构造函数 

  复制构造函数,也是构造函数。只在初始化时调用,如果定义对象后赋值,比如,t1=t2,则只是运算符重载,没有调用构造函数。

student::student(student &s)
{
    cout << "复制构造函数" << endl;
    id = s.id;
    // 使用字符指针定义的变量,需要定义复制构造函数,申请空间。
    // 也需要定义 构造函数 和 析构函数
    name = new char[strlen(s.name) + 1];
    if (name != 0)
        strcpy_s(name, strlen(s.name) + 1, s.name);
}

  调用:有四种方法。

    // 对象数组
    student stu[5] = {
        student(1,"li"),
        student(2,"wang")
    };
    stu[2].set(3, "zhao");
1、 student stucopy(stu[
0]);
2、 student stucopy_1
= stu[0];

  还可以用函数调用:

void f(student p)
{
    // 用于类对象的复制。
    cout << "此处要调用复制构造函数" << endl;
}

student stu;
stu.set(3, "zhao");
f(stu);

  还有一种情况:就是函数返回值是一个类对象,返回的是一个新的匿名对象,此处要调用复制构造函数。

student g()
{
    student stu1(1, "abc");
    return stu1;
    // 用于类对象的复制。返回的匿名对象的复制,因为 stu1 是局部变量,函数结束时要销毁。
    cout << "此处要调用复制构造函数" << endl;
}
student s = g();//此处只是换了名字,没有调用复制构造函数了

  如果匿名对象,初始化另一个同类型的对象,则匿名对象转成有名对象,不调用复制构造函数;

  如果匿名对象赋值给另一个对象,则匿名对象马上被析构;

4、匿名对象的声明周期

int run3()
{
    cout << "run3 start...." << endl;
    B(1, 2);  //执行此步,匿名对象调用构造函数后,马上调用析构函数(因为没有东西接)

    //此处,匿名函数被 b 接到了,就只调用了构造函数,匿名对象转成有名对象
    // 该有名对象是局部变量,在函数结束返回时析构(也就是 return 处)。
    B b = B(1, 2);

    cout << "run3 end...." << endl;
    return 0;
}

 

posted @ 2018-12-27 21:11  深度机器学习  阅读(1299)  评论(0编辑  收藏  举报