C++——构造函数的使用注意事项及static用法

C/C++
276
0
0
2023-02-11

1.构造函数

1.构造函数赋值和初始化列表

#include<iostream>
using namespace std;
class date
{
public:
  date(int year = 1, int month = 1, int day = 1)
  {
    //函数体赋值
    _year = year;
    _month = month;
    _day = day;
  }
  date(int year = 1, int month = 1, int day = 1)
    :_year(year), _month(month), _day(day)
  {
    //初始化列表
  }
private:
  int _year;
  int _month;
  int _day;

};
int main()
{
  return 0;
}

为什么要有初始化列表存在呢?

引用类成员

const类成员变量

自定义类型成员函数(该类没有默认成员函数)

必须放在初始化列表位置初始化

#include<iostream>
using namespace std;
class A
{
  A(int a)
    :_a(a)
  {

  }
private:
  int _a;
};
class B
{
public:
  B(int a, int ret)
    :_aobj(a)
    ,_ret(ret)
    ,_n(10)
  {
    //初始化列表
  }
private:
  int&amp; _ret;//引用
  const int _n;//const
  A _aobj;//没有默认构造函数

};
int main()
{
  return 0;
}

引用、const修饰的必须在定义的时候初始化

而自定义类型 没有默认构造函数即不用传参就可以调用的函数 (没有给它赋值)

也就需要定义的时候初始化

img

例题

#include<iostream>
using namespace std;
class A
{
public:
  A(int a)
    :_a1(a)
    ,_a2(_a1)
  {

  }
  void print()
  {
    cout << _a1 << " " << _a2 << endl;
  }
private:
  int _a2;
  int _a1;
};
int main()
{
  A aa(1);
  aa.print();
  return 0;
}

正常来说,结果应为 1 1,但是为什么变成 1 随机值?

成员变量在类中声明次序就是初始化列表的初始化顺序,与其初始化列表中的先后次序无关

_a2声明在前面

所以先初始化 _a2,先进行 _a2(_a1),而此时的_a1为随机值,所以_a2为随机值

然后才进行 _a1(a),_a1赋值成1

最终结果 为 1 随机值

隐式类型转换

#include<iostream>
using namespace std;
class date
{
public:
  date(int year)
    :_year(year)
  {

  }
private:
  int _year;
};
int main()
{
  date d1(1);//构造
  date d2 = 2;// 用2构造了一个临时对象,将用临时对象拷贝构造d2
  date d3(d1);//拷贝构造
  return 0;
}

date d2=2,相当于 date tmp(2),使用2构造一个临时对象tmp,

d2(tmp),再使用 tmp拷贝构造d2

当我们改成引用后,发现不可以实现

img

其中包含临时对象tmp,临时对象具有常性,要加 const修饰

img

explicit的使用

#include<iostream>
using namespace std;
class date
{
public:
  explicit date(int year)
    :_year(year)
  {

  }
private:
  int _year;
};
int main()
{
  date d1(1);//构造
  date d2 = 2;// 用2构造了一个临时对象,将用临时对象拷贝构造d2
  date d3(d1);//拷贝构造
  return 0;
}

若不想要隐式类型转换发生,加入关键字 explicit

static用法

例题

设计一个类A,可以计算这个类总计产生了多少对象?

自定义一定要调用 构造函数 或者 拷贝构造

方法1

设计一个全局变量n 用于统计

#include<iostream>
using namespace std;
int n = 0;//设计一个全局变量用于统计
class A
{
public:
  A()//构造
  {
    ++n;
  }
  A(const A&amp; d)//拷贝构造
  {
    ++n;
  }
};
A f1(A a)
{
  return a;
}
int main()
{
  A a1;
  A a2;
  f1(a1);
  f1(a2);
  cout << n << endl;//6
  return 0;
}

​说明一共产生了6个对象

A a1 ,A a2 ,共产生 2个对象

f1(a1)时,将a1传值给 a ,属于值传递,发生了拷贝调用

由于 f1 函数 是 值返回 ,所以 会再次发生 拷贝调用,生成一个临时对象

所以 f1(a1)共产生 2个对象

同理 , f1(a2)也产生 2个对象

共有 产生6个对象

方法2

为了防止n能随意修改

使用static修饰

#include<iostream>
using namespace std;
class A
{
public:
  A()//构造
  {
    ++n;
  }
  A(const A&amp; d)//拷贝构造
  {
    ++n;
  }
  static int getN()//使用static修饰后,没有默认this指针,函数中也不能访问非静态成员
  {
    return n;
  }
private:
  static int n;//声明,属于类的所有对象,存于静态区
};
int A::n = 0;//定义
A f1(A a)
{
  return a;
}
int main()
{
  A a1;
  A a2;
  f1(a1);
  f1(a2);
  cout << A::getN() << endl;//6
  return 0;
}

使用static,将n放在静态区中,属于类中的所有对象

img