zoukankan      html  css  js  c++  java
  • C++的构造函数们

    1.什么是构造函数?

    一种特殊的成员函数,创建一个对象时,系统需要调用对象的构造函数进行初始化,类似于OC的init方法

    2.构造函数的特点

    1. 函数名与类名一样,书写格式:类名(参数列表)
    2. 没有返回值,加上void也不行
    3. 每个类都有一个默认的公共的无参构造函数,但只要额外增加了一个构造函数,系统将不提供默认的空构造函数
    4. 构造函数可以重载,也就是说,可以提供多个构造函数

    3.构造函数的其他知识点
    如果对象是一个全局变量,那么它的构造函数调用会先于main函数

    4.什么是转换构造函数

    1. 带有一个参数的构造函数
    2. 可以将其他类型的数值转为对象

    例如:Person p(20);//前提是需要提供下面的构造函数
    直接调用转换构造函数:Person(int age)

    如果是一下代码需要分情况讨论

    Person p;

    p = 30;

    如果Person类重载了=(int)运算,第二句代码会直接用重载过的运算符进行运算

    如果没有重载,则::先隐式调用转换构造函数:Person(int age)产生一个临时的Person对象,再将临时对象赋值给p{实现是调用operator=(const Person& other)函数

    执行语句:Person temp(30);p.operator = (temp);

    }

    -------这种情况下会调用两次构造函数,第一句调用空构造函数,第二句调用转换构造函数,这种调用称为隐式调用

    5.如何阻止转换构造函数的隐式调用?

    只需要在声明只有一个参数的构造函数上加上explicit关键字(明显的)例如:

    explicit Person(int age);

    P.S.--C++创建对象数组和释放对象数组的一些问题

    Person persons[2] = {20,30}; //会调用两次转换构造函数

    Person *persons = new Person[2];//persons指向数组的第一个元素

    Person *persons = new Person[2]{20,30};跟上面一条语句一样,多了调用转换构造函数的过程

    第一种创建方法创建出来的对象数组在栈里面,不需要我们手动管理,第二三种方发创建的对象在堆里,需要手动释放

    而且释放对象数组的时候,应该用指向首元素的指针去释放,跟释放对象不一样,还要加上方括号,例如:

    delete [] persons;

    6.拷贝构造函数

    ---拷贝构造函数的基本信息

    什么是拷贝构造函数 :::只有一个参数,且参数为该类对象引用的构造函数 可以使用一个已存在的对象来初始化一个同类型的新对象 每一个类都有一个默认的公共的拷贝构造函数

    拷贝构造函数的格式::: 类名(const 类名& 参数名) { }

    加上const后,就不能在函数内部直接修改参数的成员变量

    -----------拷贝构造函数的调用以及为什么参数是引用

    Person p; Person p2(p);// 相当于 Person p2 = p;

    上面的第2行代码就会调用Person的拷贝构造函数 

    因此,用一个对象初始化另外一个对象时,系统会自动调用拷贝构造函数

    也说明了拷贝构造函数的形参不能是对象,只能是对象引用 因为调用拷贝构造函数时,需要传入一个实参对象来初始化形参对象,这时候又会调用拷贝构造函数,造成死循环

    ------------拷贝构造函数一般在什么时候被调用

    1...明显地用一个对象初始化另外一个对象 Person p; Person p2(p); // 相当于 Person p2 = p;

    2...当函数的形参是对象:调用函数时,会创建一个局部的形参对象,并且用实参对象来初始化形参对象,这里会调用拷贝构造函数 void setBook(Book book);

    3...当函数的返回值是对象:系统会利用返回的对象再创建初始化一个新的临时对象,这时也调用了拷贝构造函数 Book getBook() {  return _book; // _book是一个成员变量 }

    综上所述:一般都使用 对象引用 来取代 对象 作为函数参数或返回值

     

    C++初始化列表

    Person::Person(int age, double height) : _age(age), _height(height) {   }

    后面的: _age(age), _height(height)就是构造函数的初始化列表

    上面代码的最终效果等价于下面的代码 Person::Person(int age, double height) {     _age = age;     _height = height; }

    ----------------------但是他们的区别是什么?

    构造函数的执行分为2个阶段:

    1. 初始化阶段(对象分配内存时就进行的初始化赋值操作)
    2. 普通计算阶段(对象初始化完毕后才进行的操作)

    下面代码中成员变量的赋值是在“初始化阶段”完成的,给对象分配内存时,成员变量默认就有值了
    Person::Person(int age, double height) : _age(age), _height(height)
    {  
    }
    下面代码中成员变量的赋值是在“普通计算阶段”完成的,给对象分配好内存后,还需要执行2行代码给成员变量赋值
    Person::Person(int age, double height)
    {
        _age = age;
        _height = height;
    }
    总上所述:推荐使用构造函数的初始化列表来初始化成员变量

    ---------还有就是如果Person类的成员变量有Book类,并且Book类只提供了一个参数的构造方法(覆盖了系统提供的空构造函数)

    此时如果创建Person对象会报错,因为初始化Person之前或初始化其成员变量Book,但是Book没有空构造函数,则会报错

    此时就需要用初始化列表来初始化Book

       Person() : _book(15.0){};这样Book在分配内存的时候直接调用转换构造函数创建book对象

    -----------------初始化列表还常用与const和引用的初始化,因为如果类Person里面有

  • 相关阅读:
    HTML 转 PDF 之 wkhtmltopdf 工具精讲
    oracle学习之数据库数据保存成文件
    字体单位大小对照换算表(字号、磅、英寸、像素)
    mui 注意事项
    hbuilder header消失
    C# salt+hash 加密
    判断二个文件是否相同
    html转pdf
    Oracle中Clob类型处理解析:ORA-01461:仅可以插入LONG列的LONG值赋值
    【Django】Django 直接执行原始SQL 如何防止SQL注入 ?
  • 原文地址:https://www.cnblogs.com/xyzaijing/p/3618073.html
Copyright © 2011-2022 走看看