C++练级之路——类和对象(中)

简介: C++练级之路——类和对象(中)

1、六个默认成员函数

       我们创建一个类,如果我们什么都不写,类会自动生成六个默认成员函数;


接下来一个一个了解;

2、构造函数


       构造函数是一个特殊的函数,函数名和类名相同,主要是对类的初始化;


class Date
{
public:
  // 1.无参构造函数
  Date()
  {
    
  }
  // 2.带参构造函数
  Date(int year, int month, int day)
  {
    _year = year;
    _month = month;
    _day = day;
  }
  void Print()
  {
    cout << _year << "--" << _month << "--" << _day << endl;
  }
private:
  int _year;
  int _month;
  int _day;
};


构造函数的特性:


1.函数名和类名相同,无返回值,构造函数可以重载;

2.构造函数分为无参构造和有参构造;

3.有参构造还可以用缺省值;


例如:

//3.带缺省值的有参构造
Date(int year=2024, int month=4, int day=10)
{
  _year = year;
  _month = month;
  _day = day;
}


4.无参构造和全缺省构造不能同时调用,会报错,编译器会不知道该调用哪个;

5.如果没有写构造函数,编译器会自动生成一个构造函数,


注意:C++11 中针对内置类型成员不初始化的缺陷,又打了补丁,即:内置类型成员变量在

类中声明时可以给默认值。

例如:

private:
  int _year=1;
  int _month=1;
  int _day=1;


总结:

1、一般情况下构造函数需要我们自己去写;

2、只有少数情况下可以让编译器自动生成构造函数,类似MyQueue,成员全是自定义类型;

class stack
{
  //
};
class MyQueue
{
private:
  stack _st1;
  stack _st2;
};


3、析构函数


析构函数在类结束后清理调用的资源;

特性:

1.析构函数名是在类名前加上字符‘~';

2.无参数,无返回值;

3.一个类只有一个析构函数,若没有显式定义,编译器自动生成析构函数,析构函数不能重载;

4.对象生命周期结束后,编译器自动调用析构函数;

5.当类中没有申请资源时,可以不写析构函数,例如Date类,有资源申请时一定要写,否则会造成资源泄露,如stack;


4、拷贝构造


拷贝构造函数:只有一个形参;

特性:

1.拷贝函数也是构造函数的重载,

2.拷贝构造函数参数只能有一个,必须是类类型对象的引用,如果直接传类,编译器会报错,会引发无穷递归;

3.如果没有显式定义,编译器会自动生成默认的拷贝函数,默认的拷贝函数是浅拷贝或者值拷贝,就是不额外开辟空间,遇到一些需要额外开辟空间的类就不适用了;

class Date
{
public:
  //有参构造函数
  Date(int year=2024, int month=4, int day=11)
  {
    _year = year;
    _month = month;
    _day = day;
  }
  //拷贝构造函数
    //d是d1的引用
  Date(Date& d)
  {
    _year = d._year;
    _month = d._month;
    _day = d._day;
  }
  void Print()
  {
    cout << _year << "-" << _month << "-" << _day << endl;
  }
 
private:
  int _year;
  int _month;
  int _day;
};
 
int main()
{
  Date d1;
  d1.Print();
  Date d2 = d1;
  d2.Print();
 
  return 0;
}


注意:

类中如果没有涉及资源申请,可以不写拷贝构造函数,一旦涉及到资源申请,拷贝函数就是要写的,否则就是浅拷贝;

例如:

typedef int DataType;
 
class Stack
{
public:
  Stack(size_t capacity = 3)
  {
    cout << "Stack(size_t capacity = 3)" << endl;
 
    _array = (DataType*)malloc(sizeof(DataType) * capacity);
    if (NULL == _array)
    {
      perror("malloc申请空间失败!!!");
      return;
    }
    _capacity = capacity;
    _size = 0;
  }
 
  void Push(DataType data)
  {
    // CheckCapacity();
    _array[_size] = data;
    _size++;
  }
 
  void Print()
  {
    for (int i = 0; i < _size; i++)
    {
      cout << _array[i] << " ";
    }
    cout << endl;
  }
  // 其他方法...
  ~Stack()
  {
    cout << "~Stack()" << endl;
 
    if (_array)
    {
      free(_array);
      _array = NULL;
      _capacity = 0;
      _size = 0;
    }
  }
private:
  DataType* _array;
  int _capacity;
  int _size;
};
int main()
{
  Stack d1;
  d1.Push(1);
  d1.Push(2);
  d1.Push(3);
  d1.Print();
  Stack d2 = d1;
  d2.Print();
  return 0;
}


该程序会发生崩溃,因为没有写拷贝构造函数,编译器默认的拷贝构造是浅拷贝,导致d1和d2指向同一块空间,调用两次析构函数析构同一块空间,程序崩溃;

相关文章
|
9天前
|
存储 编译器 C++
【c++】类和对象(中)(构造函数、析构函数、拷贝构造、赋值重载)
本文深入探讨了C++类的默认成员函数,包括构造函数、析构函数、拷贝构造函数和赋值重载。构造函数用于对象的初始化,析构函数用于对象销毁时的资源清理,拷贝构造函数用于对象的拷贝,赋值重载用于已存在对象的赋值。文章详细介绍了每个函数的特点、使用方法及注意事项,并提供了代码示例。这些默认成员函数确保了资源的正确管理和对象状态的维护。
36 4
|
10天前
|
存储 编译器 Linux
【c++】类和对象(上)(类的定义格式、访问限定符、类域、类的实例化、对象的内存大小、this指针)
本文介绍了C++中的类和对象,包括类的概念、定义格式、访问限定符、类域、对象的创建及内存大小、以及this指针。通过示例代码详细解释了类的定义、成员函数和成员变量的作用,以及如何使用访问限定符控制成员的访问权限。此外,还讨论了对象的内存分配规则和this指针的使用场景,帮助读者深入理解面向对象编程的核心概念。
33 4
|
1月前
|
存储 编译器 对象存储
【C++打怪之路Lv5】-- 类和对象(下)
【C++打怪之路Lv5】-- 类和对象(下)
27 4
|
1月前
|
编译器 C语言 C++
【C++打怪之路Lv4】-- 类和对象(中)
【C++打怪之路Lv4】-- 类和对象(中)
23 4
|
1月前
|
存储 安全 C++
【C++打怪之路Lv8】-- string类
【C++打怪之路Lv8】-- string类
21 1
|
1月前
|
存储 编译器 C语言
【C++打怪之路Lv3】-- 类和对象(上)
【C++打怪之路Lv3】-- 类和对象(上)
16 0
|
1月前
|
存储 编译器 C++
【C++类和对象(下)】——我与C++的不解之缘(五)
【C++类和对象(下)】——我与C++的不解之缘(五)
|
1月前
|
编译器 C++
【C++类和对象(中)】—— 我与C++的不解之缘(四)
【C++类和对象(中)】—— 我与C++的不解之缘(四)
|
1月前
|
编译器 C语言 C++
C++入门3——类与对象2-2(类的6个默认成员函数)
C++入门3——类与对象2-2(类的6个默认成员函数)
23 3
|
1月前
|
C++
C++番外篇——对于继承中子类与父类对象同时定义其析构顺序的探究
C++番外篇——对于继承中子类与父类对象同时定义其析构顺序的探究
53 1