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

    构造函数是特殊的成员函数,只要创建类类型的新对象,都要执行构造函数,定义对象指针不会调用构造函数。 

    创建类类型的新对象时,编译器为对象分配内存空间,完成后自动调用构造函数初始化对象的数据成员。

    构造函数的主要工作是初始化对象的数据成员。

    0、构造函数的特点

    (1)、构造函数与类同名

    (2)、构造函数没有返回类型

    (3)、构造函数可以重载,一个类声明的构造函数的数量没有限制

    (4)、构造函数由系统自动调用,不允许显示调用

    (5)、构造函数必须声明为类的公有成员(否则会编译出错,VS提示构造函数不可访问,g++提示构造函数是私有的)

    (6)、构造函数像其他任何函数一样,可以没有形参,也可以定义多个形参 

    (7)、构造函数不能声明为常成员函数(fun(...)const{}),可以声明为inline(内联)函数

     

    1、无参构造函数 

    1.1、默认构造函数 

    只有当一个类没有定义构造函数时,编译器才会自动生成一个默认构造函数。
    这条规则的根据是,如果一个类在某种情况下需要控制对象初始化,则该类很可能在所有情况下都需要控制。 

    1.2、所有参数都有默认值的构造函数

    如果显式定义了无参数的构造函数,又定义了所有参数都有默认值的构造函数,那么定义对象时会产生二义性, 导致编译错误。

    #include <iostream>
    using namespace std;
    
    class Example
    {
    public:
        Example(){cout<<"The Constructor without parameter"<< endl;}
    //  Example(int nu = 0){num = nu; cout << "The Constructor with default all value default parameter" << endl;}
    private:
        int num;
    };
    
    int main(void)
    {
        Example ex;
        Example exarr[2];
        return 0;
    }

    2、带参数的构造函数

    构造函数可以重载,所以构造函数的行参多种多样。注意下例中注释掉的2个函数 和 第二个函数不能形成重载关系。

    class Example
    {
    public:
        Example(int im){m = im;}
        Example(int im, int in){m = im; n = in;}
    //  Example(int im, int in = 0){m = im; n = in;}
    //  Example(int im = 0, int in = 0){m = im; n = in;}
    private:
        int m;
        int n;
    }; 

    缺省参数的规则见:http://www.cnblogs.com/LubinLew/p/DefaultParameters.html

     

    3、拷贝构造函数

    3.1、调用拷贝构造函数的情形

    在C++中,下面三种对象需要调用拷贝构造函数(有时也称“复制构造函数”):
    1) 一个对象作为函数参数,以值传递的方式传入函数体;
    2) 一个对象作为函数返回值,以值传递的方式从函数返回;
    3) 一个对象用于给另外一个对象进行初始化; 
    class X{...};
    
    //1
    X obj1,
    X obj2(obj1); //一个对象用于另一个对象的初始化
    X obj3(obj2); //一个对象用于另一个对象的初始化
    //2 X func1(...){} //函数返回对象,linux下可能不掉用拷贝构造函数 //3 ... func2(X obj...){...} //函数有对象参数 //4 X func3(X obj){...} //调用2次拷贝构造函数 

    3.2、定义拷贝构造函数的原则

    对于凡是包含动态分配成员或包含指针成员的类都应该提供拷贝构造函数;
    ②在提供拷贝构造函数的同时,还应该考虑重载"="赋值操作符号。
    拷贝构造函数必须以引用的形式传递(参数为引用值)。其原因如下:
    当一个对象以传递值的方式传一个函数的时候,拷贝构造函数自动的被调用来生成函数中的对象。
    如果一个对象是被传入自己的拷贝构造函数,它的拷贝构造函数将会被调用来拷贝这个对象这样复制才可以传入它自己的拷贝构造函数,
    这会导致无限循环直至栈溢出(Stack Overflow)。

    3.3、举例

    注意:在linux下,函数返回类的对象时,不调用拷贝构造函数

    #include <iostream>
    using namespace std;
    
    class Example
    {
    public:
        Example(){m = 0; cout << "Default Constructor" << endl;}
        Example(const Example& ref){m = ref.m;cout << "Copy Constructor"<<endl;}
        Example& operator=(const Example& ref){m = ref.m; cout << "Overload Operator =" << endl;return (*this);}
        void SetData(int n){m = n;}
        void display(void){cout << m << endl;}
    private:
        int m;
    };
    
    Example Func1(void)
    {
        Example ex;            //Default Constructor
        ex.SetData(5);
        return ex;
    }
    void Func2(Example ex){}
    
    Example Func3(Example ex)
    {
        return ex;
    }
    int main(void)
    {
        Example ex1;        //Default Constructor
        cout << ">>>Init" << endl;
        Example ex2(ex1);    //Copy Constructor
        Example ex3 = ex1;    //Copy Constructor
    
        cout << ">>>Func1 <1>" << endl;
        Func1();
        cout << ">>>Func1 <2>" << endl;
        Example ex4 = Func1();
        ex4.display();
    
        cout << ">>>Func2" << endl;
        Func2(ex3);            //Copy Constructor
    
        cout << ">>>Func3" << endl;
        Func3(ex4);            //Copy Constructor
    
        cout << ">>> = " << endl;
        ex3 = ex1;
    
        return 0;
    }  

    4、初始化列表(constructor initializer list)

    指定类的数据成员的初始值。在构造函数体现执行前,用初始化列表中指定的值初始化成员。
    没有在初始化列表中初始化的类成员,使用它们的默认构造函数隐式初始化。静态成员变量不能使用初始化列表初始化,也不能在构造函数中赋值.

    必须用到初始化成员列表的四种情况 

    1) 初始化一个引用成员
    2) 初始化一个const成员
    3) 基类没有默认构造函数和无参构造函数
    4) 类中有一个类对象数据成员,并且对象的类没有默认构造函数和无参构造函数.

    #include <iostream>
    using namespace std;
    
    class Base
    {
    public:
        Base(int n):num(n){cout<<"Base Constructor("<<n<<")"<<endl;}
    private:
        int num;
        static int stn;//cannot initialize static class data via constructor
    };
    int Base::stn = 0;
    
    class Derived:public Base//④基类(没有默认构造函数和无参构造函数)
    {
    public:
        Derived(int i, int n, Base& bref, int& ire, int ibs):ival(i),bs(n),bsref(bref),iref(ire),Base(ibs)
        {cout<<"Derived Constructor"<<endl;}
    private:
        const int ival;    //①const数据成员
        Base bs;           //②类成员对象(没有默认构造函数和无参构造函数)
        Base& bsref;       //③引用(对象的引用)
        int& iref;         //③引用(普通数据类型引用)
    };
    
    int main()
    {
        int i = 10;
        Base bs(1);
    
        Derived(1,2, bs, i, 3);
    
        return 0;
    } 

    5、构造函数的调用顺序

    http://www.cnblogs.com/LubinLew/p/Cpp-CallOrderOfConstructorAndDeconstructor.html

     

     

     

     

     

     

  • 相关阅读:
    [CodeForces]Codeforces Round #429 (Div. 2) ABC(待补)
    About Me
    2018-06-14
    Codeforces Codeforces Round #484 (Div. 2) E. Billiard
    Codeforces Codeforces Round #484 (Div. 2) D. Shark
    Codeforces Educational Codeforces Round 44 (Rated for Div. 2) F. Isomorphic Strings
    Codeforces Educational Codeforces Round 44 (Rated for Div. 2) E. Pencils and Boxes
    Codeforces Avito Code Challenge 2018 D. Bookshelves
    Codeforces Round #485 (Div. 2) D. Fair
    Codeforces Round #485 (Div. 2) F. AND Graph
  • 原文地址:https://www.cnblogs.com/LubinLew/p/Cpp-ConstructorFunction.html
Copyright © 2011-2022 走看看