【c++】构造函数和析构函数{生可带来,死不带去}

构造函数:

对象和内存的关系:

有空间不一定有对象。
有对象一定有空间。

class Empty
{
};
int main()
{  //看不见构造函数,是因为,只要程序运行,系统会调用默认构造函数,创建对象
   Empty e;   //占位符,有对象,一定要有空间
   cout<<sizeof(e)<<endl;
   Empty *p = &e;  //如果e没空间,指向哪?
}

1.1 构造函数的用途:

1.创建对象
2.初始化对象中的属性。
3.类型转换

类型转换:

class Int
{
public :
Int(x = 0):value(x){}
}
int main()
{
Int ix (12);
int a = 200;
ix = a; //赋值给ix的时候,会创建调动构造函数一个无名对象,将a传给ix(完成了类型转换。)
}

  1. 构造函数的返回值是构造函数创建的对象。(系统分配的空间中)
  2. 在程序运行的时,当新的对象被建立,该对象所属的类的构造函数自动被调用,在该对象的生存期中也只调用一次。
    请添加图片描述
    不可以重新构建c1对象,因为没调动一次构造函数,就会创建一个对象/
    但是new(&c1) Comlex(200,300),可以让c1再构建一次。
  3. 【构造函数可以重载】,严格意义上讲,类中定义了多个构造函数:,(每个构造函数中可以完成不同的属性,生可带来,死了带不走,直接析构了)
class Complex
{
     double Real;  
     double Image;
     public:
         Complex(){}
         Complex(double r,double i)//函数重载
         {
               Real = r;
               Image = i;
         }
         fun(Complex cx)
         {}
}
int main()
{
     Complex c1; //调用的Complex()默认构造函数
     Complex c2(1.1,2.2);//调用的是Complex(double r,double i)
     Complex c3();//一定要写数据,负责会被认为是函数的声明
     complex c4{};//可以,列表的初始化方案
     fun(Complex(2,3));//构造函数一定要获取某个空间,在某个空间构造对象。
     
}

Complex c3();/一定要写数据,负责会被认为是函数的声明
4. 构造函数可以在类中定义,也可以在类外定义
5. 如果类说明中没有给出构造函数,C++编译器会自动生成一个缺省构造函数
complex(){}
只要我们自己定义一个构造函数,系统就不会自动生成缺省构造函数,
如果构造函数不带参数或者带参数没有缺省值(如下图),就会被认为缺省构造函数。
请添加图片描述

关键字:sizeof(),编译期确定大小。
构造函数一定要获取某个空间,在某个空间构造对象。

1.2 构造函数具有this指针:

class Complex
{
  private:
     double Real;  
     double Image;
     public:
         Complex(){}//Complex(Complex *const this)
}
 Complex c1; Complex(&c1)

1.3 结构体和类的区别:

struct 内默认为public
class 内默认为private

struct str
{
   int a;
   char b;  //可以通过str s; s.a =1,s.b = "s";进行初始化
}
class Com
{
   privateint  real;  //private: int real;int image;
     public :            //public: Com(int r = 0,int i = 0)
           int  image         // Com c3{3,4}   Com c2 = {2}; 均可初始化,从右往左
}
int main()
{
    Com c1 = {1}; //错误,
    Com c2 = {2}; //错误 必须是成员属性均为公有,才可以初始化,
                 //系统会自动提供一个有两个形参的构造函数。
                 // Com(int ,int);
     Com c3{3,4}   ;        
  }                  
  • 缺省构造函数是否有【形参】取决于定义的成员属性公有还是私有
    公有如下图:有几个属性,缺省构造函数就有几个形参,并且每个形参的缺省给为0
    请添加图片描述
    私有如下图
    请添加图片描述

1.4 对构造函数使用初始化列表:

初始化和设计顺序必须相同。

class Complex
{
  private:
     double Real;  
     double Image;
     public:
         Complex():real(0),image(0)//成员初始化列表
         {}
          Complex(double r,double i):real(r),image(i)
         {
               Real = r;
               Image = i;
         }
}

可能出现的问题:

class Complex
{
private:
    int real;
    int image;    
public:                    
    Complex(int x) :image(x), real(image) {}//read(x),image(real)可以
    void print()
    {
        cout << "real:" << real << "image:" << image << endl;
    }
};
int main()
{
    Complex c1(10);
    c1.print();

}

列表初始化的顺序最好和属性定义的顺序相同,否则如图。
请添加图片描述
类中定义了多个构造函数,:向现实靠拢,每个人的出身不同,所带的属性也就不同

1.5 构造函数可以用引用的方式返回。

int &Real()    ,相当于返回this指针指向对象的别名
{
    return real;
 }

析构函数:

【对象的生存期满了就会自动调用。】


用构造函数创建对象后,程序负责跟踪对象,当对象使用结束,系统就会调用析构函数,完成对对象的清理。
注意:
1.析构函数不可重载,无可见参数
2.析构函数如果自己没有实现,系统会默认生成一个。
语法:~函数名()

  1. 局部对象,在函数调用点处创建对象,函数结束,对象被析构,先创建的后析构
  2. 静态局部对象(在数据区):等这个程序结束的时候才会被析构。
  3. 全局对象(全文见可见):当程序进入main之前,对象已经定义,整个程序结束,对象才会析构调。(静态全局对象,本文件可见。)
 Complex c1(1,1);
 int main()
{
    cout<<"begin main"<<endl;
    Complex c1(10);
    cout<<"end main:"<<endl;
    return 0;
}
Complex c3(3,3);

不论全局函数在哪,在进入主函数之前都会定义好,请添加图片描述


4.块内对象:进入块中调用构造函数创建对象,从块中出来,析构对象。
//只在块中有效

 int main()
{
    cout<<"begin main"<<endl;
    Complex c1(11);
    cout<<"begin 块:"<<endl;
    {
        Complex c2(2,2);
    } //这个位置块内对象析构
    cout<<"end 块"<<endl;
    cout<<"end main"<<endl;
    return 0;
}

请添加图片描述

  • 不能控制生,但可以控制死。(可以主动调用析构函数,析构对象)
    一般不要这样,系统无法记录析构函数调动了几次,因此自己析构了,但是系统还会再析构。
 int main()
{
    Complex cs(11);
   //
   cs.~Complex(); //主动调动。
   return 0;
}

5.动态创建的对象, 使用new创建对象,delete释放对象

 int main() 
{
    int n = 5;
 //   Complex* xp = new Complex[n]{{1,2},{},{4,5},{6,7}};//1.申请堆空间2.创建对象(调用的是有参的构造函数)                         
                                       //  {}调用的是无参构造函数
     Complex* xp = new Complex{}; 
   // xp -> print();   
    for(int i = 0;i<n;i++)
    {
       xp[i].Print();  //申请了一组对象
    }
  //  delete xp; //1.析构对象,将内存还给申请空间,2.将申请的空间还给堆
    delete []xp;
    xp = nullptr;
}

请添加图片描述
有空间不一定有对象,必须要调用构造函数创建对象。
所以,不能调用对象的方法。
有对象才可以对空间进行操作。
如下:

int main()
{
    Complex *xp = (Complex*)malloc(sizeof(Complex));//只申请空间,没有兑现
    //调动构造函数再new指定的xp申请的空间中构建对象
    new (xp) Complex{2,3};//定位new,构建对象。这样
    xp->print();                   // xp才可以访问对象的方法。
   xp->~Complex();//主动析构对象。
    free(xp);
    xp = NULL
}

所以malloc + 定位new实现了 new 的功能。


成员方法的设计

  1. 常对象只能调动常方法
  2. 普通对象可以调动普通方法,也可以调动常方法
  3. 普通对象优先调用普通方法
    原因:对象调用类中的方法,本质上是将对象的地址传给this指针,因此对象被const修饰,在被this指针指向的时候,能力只能缩小,不能扩大。

当类中的成员属性设置为私有的时候,可以通过成员方法访问或修改成员属性。
如:

class Complex
{
    private:
          int  num;
          int  age;
    public:
          int set_num(int n)
          {
               num  = n;
          }
          // int set_age(const Complex *const this ,int a) 
          int set_age(int a) const //常方法  但是导致无法对age进行赋值
          {
              age = a;
          }
           int get_num() const   //在获取数据的时候加const,只读不写
          {
              return num;
          }
             int get_age() const
          {
              return age;
          }
          
          
}
int main()
{
    Complex cc;
    cc.set_num(10);  //通过成员方法。。。
    const Complex ss;  //常对象  ,约束的是指向能力,一般用于获取数据
     ss.set_age(20);  //只能访问常方法
     cc.set_age(10);//也可以。能力缩小 导致无法写入数据
     //在获取数据的时候加const,只读不写
     ss.get_age();
     cc.get_num();
     }

常方法里只能调动其他常方法。

主要就是this指针的可访问性权限,指向的能力
如下:

class Complex
{
    private:
          int  num;
          int  age;
    public:
          int set_num(int n)
          {
               num  = n;
          }
          //int print(const Complex *const this,int n)
          int print(int n)const
          {
             //
             this->set_num(n)//错误,因为set_num(n) 相当于set_num(this,n),print的this 放入sert_num,能力被扩大
          }
          // int set_age(const Complex *const this ,int a) 
          
           int get_num() const   //在获取数据的时候加const,只读不写
          {
               this->print();//  print(this)  常方法可以调用常方法
              return num;
          }
             int get_age() 
          {  
             this->print();  //普通方法也可以调用常方法,因为可以this指针传给print的this,能力被缩小。
              return age;
          }
          
          
}
  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值