默认构造函数

1、构造函数

一、什么是构造函数

c++中有一种特殊的成员函数,他的名字和类名相同,没有返回值,而在创建对象时会自动执行,类中的数据成员的初始化往往通过构造函数来实现。完成类中数据成员的初始化,同时也是类中的成员函数,但是比较特殊

二、如何给构造函数传参

有参构造,在定义对象是=时给出实参:类名 实例名(实参1,实参2,.....)

构造函数不需用户调用,也不能被用户调用,在创建对象时会被自动调用,但是在声明一个类的指针对象时,构造函数不会被调用,当new一个空间的时候,构造函数也会被调用。

如果用户自己没有定义构造函数,则C++系统会自动生成一个构造函数,只是这个构造函数的函数体是空的,也没有参数,不执行初始化操作。

在构造函数的函数体中不仅可以对数据成员赋初值,而且可以包含其他语句。但是一般不提倡在构造函数中加入与初始化无关的内容,以保持程序的清晰。

对于无参构造函数,在创建对象时,不可以写成:类名 对象名()

//构造函数的主要功能是完成类中数据成员的初始化,同时它也是类中的一个成员函数,但是比较特殊
class stu
{
    public:
        string name;
        int age;

       /* stu(string n,int a,int myid)
        {
            cout << "构造函数" << endl;
            name = n;
            age = a;
            id = myid;
        }*/

        stu()
        {
            name = "temp";
            age = 0;
            id = 100;
        
        }

        void print()//根据有无形参,构造函数分为:有参构造函数 和无参构造函数
        {
            cout << name << age<<":"<
class stu
{
    public:
        string name;
        int age;

       stu(string n,int a,int myid) //一个类中可以存在多个构造函数
        {
            cout << "构造函数" << endl;
            name = n;
            age = a;
            id = myid;
           // print();
        }

        stu()//在C++中,无参构造函数也称为默认构造函数,如果构造函数提供的形参全是默认形参类型,则该构造也属于默认构造函数
        {
            name = "temp";
            age = 0;
            id = 100;
        
        }

        void print()//根据有无形参,构造函数分为:有参构造函数 和无参构造函数
        {
            cout << name << age<<":"<

int add(int num1,int num2)
{

    return num1 + num2;
}

int sub(int num1, int num2)
{

    return num1 - num2;
}

int mul(int num1, int num2)
{

    return num1 * num2;
}


int   div1(int num1, int num2)
{

    return num1 / num2;
}


int main()
{
    
    int num1, num2;
    cin >> num1 >> num2;
 cout<<   add(num1, num2)<> num1 >> num2;
 //cout<<   add(num1, num2)<

三、参数初始化列表

成员初始化表的一般形式为:

构造函数名(【参数表】):数据成员名1(初始值1),数据成员2(初始值2),,,,,,,,,,

{

         //构造函数体

}

1、执行带参数初始化列表的构造函数时,先执行初始化列表,后执行构造的函数体代码

2、初始化列表可以用于全部成员变量,也可以只用于部分成员变量

3、初始化的顺序和其在类中声明时的顺序是一致的,与列表的先后顺序无关

4、成员初始化列表只能用于构造函数

class stu
{
public:
    string name;
    int age;
    const int a;//常数据成员
    int& temp;//引用类型的数据成员   name("laoguo")  name="laoguo"

    //初始化列表中的成员的初始化顺序和书写顺序无关,和成员在类中的定义顺序有关
    stu(int kk):a(10),name("laoguo"),temp(kk) //当构造函数中的形参比较多时,用初始化列表可以提高程序的性能
    {
        age = 12;
      /*  name = "";
        age = 12;
        a = 1000;*/
      
    }

    void print()
    {
        cout << name << age << ":" << id << endl;

    }


private:
    int id;

};



int main()
{
    stu s1(30);
    s1.print();

    
    return 0;
}
class date
{
public:
    int year;
    int month;
    int day;
    date(int y, int m, int d) //一旦类中用户提供了构造函数,系统不会在为该类自动生成
    {
        year = y;
        month = m;
        day = d;

    }

    /*date()
    {
        year = 0;
        month = 0;
        day = 0;
    }*/


};

class stu
{
public:
    string name;
    int age;
    date bir;//3.当用另一个类对象作为当前类的数据成员时,如果该类没有提供默认构造函数,此时需要通过初始化列表的方式来初始化该对象。
    stu(string n, int a, int y, int m, int d):bir(y,m,d)
    {
        name = n;
        age = a;

    
    }

  

};



int main()
{
 

    
    return 0;
}

四、默认构造函数

默认构造函数_第1张图片

2、拷贝构造函数

对类中的数据成员进行初始化

需要用到多个完全相同的对象,要将对象在某一个瞬间的状态保留下来,这就是对象的赋值机制,用一个已有的对象快速地复制处多个相同的对象,如Box1,Box2(Box1)去克隆处一个新对象Box2。

拷贝构造函数的本质是定义对象之间的规则,确定了那些成员需要拷贝,那些不需要拷贝

拷贝构造函数的一般格式:A(const A & a)

class stu
{
public:
    string name;
    int age;

    stu(string n,int a,int myid)
    {
        name = n;
        age = a;
        id = myid;
    }

    stu() {}
    void print()
    {
        cout << name << age <<"#" << id << endl;

    }

private:
    int id;


};



int main()
{
    stu s1("laogup", 23,1001);
    stu s2;
    //通过赋值运算符,可以将=右边对象的所有数据成员拷贝到=左边的对象中,用赋值实现拷贝是全拷贝。
    s2 = s1;//同类型的对象之间可以相互赋值,主要将一个对象中的数据成员值赋值给另外一个对象

    //如果在实现对象间拷贝的时候 你想有所选择的拷贝,需要通过拷贝构造函数




    s2.print();

    
    return 0;
}
class stu
{
public:
    string name;
    int age;
    string s_name;

    stu(string n,int a,string sname)
    {
        cout << "普通构造函数" << endl;
        name = n;
        age = a;
        s_name = sname;
      
    }

    //拷贝构造函数 特点:只有一个形参并且该形参属于当前所在类的类类型,拷贝构造的形参不能采用值传递
    stu(const stu& temp)
    {
        cout << "拷贝构造函数" << endl;//定义temp与当前对象之间的拷贝原则
        name = "";
        age = 0;
        s_name = temp.s_name;
    
    }
    stu() {}
    void print()
    {
        cout << name << age<<"#" << s_name << endl;

    }




};



int main()
{
    stu s1("laoguo", 23,"建大华清");
  
   // stu s2(s1);//实现了用s1对象来初始化s2对象  ,如果用户没有定义拷贝构造,系统会自动生成一个,并实现全拷贝
    stu s2 = s1;// stu s2(s1) 都匹配的是拷贝构造函数
   /* stu s2;
    s2 = s1;*/

    s2.print();//0#建大华清

    
    return 0;
}
class stu
{
public:
    string name;
    int age;
    string s_name;

    stu(string n,int a,string sname)
    {
        cout << "普通构造函数" << endl;
        name = n;
        age = a;
        s_name = sname;
      
    }

    //拷贝构造函数 特点:只有一个形参并且该形参属于当前所在类的类类型,拷贝构造的形参不能采用值传递
    stu(const stu& temp)
    {
        cout << "拷贝构造函数" << endl;//定义temp与当前对象之间的拷贝原则
        name = "";
        age = 0;
        s_name = temp.s_name;
    
    }
    stu() {}
    void print()
    {
        cout << name << age<<"#" << s_name << endl;

    }




};

void test(stu tt)
{


}

stu mytest()
{
    stu s2("ttt", 44, "sdf");
    return s2;//3 在函数中返回一个对象


}


int main()
{
    stu s1("laoguo", 23,"建大华清");
  
    test(s1);//2用一个对象做值传递

   // 1. stu s2(s1);

    mytest();
    
    return 0;
}

3、析构函数

析构函数是一个特殊的由用户定义的成员函数,当该类的对象离开了他的域(对象的生命周期结束时)或者delete表达式应用到一个该类的对象的指针上时,析构函数会自动被调用

析构函数的名字是在类名前加上波浪线~,他不返回任何值,也没有任何参数,我们可以为一个类定义多个构造函数,但是我们只能提供一个析构函数,他将应用于类的所有对象上。

主要功能是做清理和收尾

class stu
{
public:
    string name;
    int age;
    string s_name;

    stu(string n,int a,string sname)
    {
        cout << "普通构造函数" << endl;
        name = n;
        age = a;
        s_name = sname;
      
    }


    stu() { cout << "默认构造函数" << endl; }
    void print()
    {
        cout << name << age<<"#" << s_name << endl;

    }
    //析构函数: ~类名(){}    不需要用户主动调用,当某个对象在离开它的域就会触发 该对象所属类中的析构函数
    ~stu() //析构函数的作用:清理收尾工作
    {
        cout << "析构函数" << endl;
 
    }



};

void test()
{
    static stu s3;

}




int main()
{
    stu s1;
    test();
    cout << "#############" << endl;
    stu s2;

    return 0;
}

4、匿名对象

只存在于构造该对象的那行代码,离开构造对象的哪行代码后立即调用该对象

int main()
{
  //匿名对象的创建:类型(【实参列表】),他的生存周期只存在于改行代码
  stu();//类名 对象名(【实参列表】)
  cout<<"#######"<

 5、this关键字

class stu
{
public:
    string name;
    int age;
    string s_name;
    // const int *a        int * const a
    stu(string name,int age,string s_name)//在C++中,一般来说 成员函数中都有一个隐形的形参叫this     this == stu * const this
    {
        cout << "inner:"<name = name;//1.当成员函数中 局部变量与类中的数据成员出现重名 ,此时可以通过this关键字来加以区分 
        this->age = age;
        this->s_name = s_name;
      
    }



    void print()
    {
        cout << name < age<<"#" << s_name << endl;

    }
   
    stu mytest()
    {
        return *this;//2.  返回当前对象
    
    }


};






int main()
{

    stu s1("laoguo", 12, "建大");
    cout << "outer" << &s1<< endl;
    stu s2("laoguo1", 12, "建大");
//inner:00A0FAFC
//outer00A0FAFC
    return 0;
}

6、对象的动态建立和释放

如果我们希望在需要用到对象时才建立对象,在不需要用该对象时就撤销它,释放它所占的内存空间以供别的数据使用,除了沿用C语言提供的malloc与free函数外,还可以:

在c++利用new操作符在堆区开辟数据空间,手动开辟就需要手动释放,释放时利用delete操作符。

一、new运算符

作用:分配内存(堆上),调用构造函数

一般格式:new 类型(初值单值)

                  new 类型 {初值多值}

                   new类型【大小】;

二、delete运算符

例子:


class stu
{
public:
    string name;
    int age;
    string s_name;

    stu(string name,int age,string s_name)
    {
        cout << "inner:"<name = name;
        this->age = age;
        this->s_name = s_name;
      
    }



    void print()
    {
        cout << name < age<<"#" << s_name << endl;

    }

    ~stu()
    {
        cout << "析构函数" << endl;
    
    }
   
   
};






int main()
{
    //在堆上创建单对象和释放单个对象的案例
   int *pt= new int;//在堆上构建一个int大小的内存并返回给内存的首地址
   *pt = 1000;//对堆对象进行写操作
   cout << *pt << endl;//进行读操作

   int* pt1 = new int(10);//在堆上创建一个int对象 同时将其初始化为10
   cout << *pt1 << endl;


   stu* pp = new stu("laoguo",22,"北大");//在堆上构建一个类类型对象stu
   cout << pp->name << endl;
   pp->print();
   
   //new和delete要成对出现
   delete pp;//当对一个堆对象施加delete 也会触发该类的析构函数


    return 0;
}
class stu
{
public:
    string name;
    int age;
    string s_name;

    stu(string name,int age)
    {
        cout << "inner:"<name = name;
        this->age = age;
       
      
    }



    void print()
    {
        cout << name < age<< endl;

    }

    ~stu()
    {
        cout << "析构函数" << endl;
    
    }
   
   
};





//批量在堆上构建对象的案例
int main()
{

  //  int* pt = new int[10]; //在堆上构建一个可以容纳10个整数类型的数组;
    //int* pt = new int[10]{ 11, 22, 33, 1, 2, 3, 4, 5, 6, 7 };//构建动态数组的同时并完成其整体的初始化
    //for (int i = 0; i < 10; i++)
    //{
    //    cout << pt[i] << endl;
    //}

    stu* pp = new stu[3]{ {"kk",3},{"pp",5},{"yy",7}};
    for (int i = 0; i < 3; i++)
    {
        cout << pp[i].name << pp[i].age << endl;
    }

    delete[] pp;

    return 0;
}

7、共用数据的保护(const)

一、常对象

格式:const <类名> <对象名>;

<类名> const <对象名>;

//常对象的 案例

class stu
{
public:
    string name;
    int age;

    stu(string name,int age)
    {
        cout << "inner:"<name = name;
        this->age = age;
       
      
    }

    void test(string ljs)
    {
        name = ljs;
    
    }

    void print()
    {
        cout << name < age<< endl;

    }

    ~stu()
    {
        cout << "析构函数" << endl;
    
    }
   
   
};






int main()
{

    //通过常对象,可以访问类中的数据成员,但是不可以对其做修改。一旦定义了常对象 相当于对类中的所有数据成员都加了const 约束
    const stu s1("laoguo", 22);//定义一个stu类型的常对象

    cout << s1.name << endl;
    //s1.test(); 常对象不可以调用类中的非 常成员函数
   //  s1.name = "laozhang"; 是错的




    return 0;
}

二、常数据成员

//常数据成员的使用案例
class stu
{
public:
    string name;
    int age;
    const int score;//常数据成员,不要试图对常数据成员中的值进行修改,但是可以读

    stu(string name,int age,int sc):score(sc)//对与常数据成员需要通过初始化列表来对其初始化
    {
        cout << "inner:"<name = name;
        this->age = age;
       
      
    }

    

    void print()
    {
        cout << name < age<

三、常成员函数

//常成员函数 使用案例

class stu
{
public:
    string name;
    int age;
    const int score;//常数据成员,不要试图对常数据成员中的值进行修改,但是可以读

    stu(string name,int age,int sc):score(sc)//对与常数据成员需要通过初始化列表来对其初始化
    {
        cout << "inner:"<name = name;
        this->age = age;
       
      
    }
    //常成员函数
    void mytest()const
    {
        cout << age << endl;
        cout << "加const的函数";
      //  age = 33;//在常 成员函数眼中,类中的任何数据成员都是神圣不可侵犯(只能读不可以改)
        //print();是错的,在常成员函数中 不可以调用类中非 常成员函数
    }

    //void mytest()//在类中 重载时 有一个特殊的情况,就是函数后加const 和不加const 可以重载成功
    //{
    //    cout << "不加const的函数";
    //
    //}

    void print()
    {
        cout << name < age<

你可能感兴趣的:(算法)