简述类与对象---中

203 阅读4分钟

类的默认成员函数

如果一个类中没有任何对象,并不意味着什么都没有,类里面还又默认的六个成员函数

构造函数

构造函数与类名是相同的,不需要用户主动调用当然也不能主动调用,创建对象时自动生成,这就是构造函数

1.  #include <iostream>
1.  u[sin](http://c.biancheng.net/ref/sin.html)g namespace std;
1.
1.  class Student{
1.  private:
1.  char *m_name;
1.  int m_age;
1.  float m_score;
1.  public:
1.  //声明构造函数
1.  Student(char *name, int age, float score);
1.  //声明普通成员函数
1.  void show();
1.  };
1.
1.  //定义构造函数
1.  Student::Student(char *name, int age, float score){
1.  m_name = name;
1.  m_age = age;
1.  m_score = score;
1.  }
1.  //定义普通成员函数
1.  void Student::show(){
1.  cout<<m_name<<"的年龄是"<<m_age<<",成绩是"<<m_score<<endl;
1.  }
1.
1.  int main(){
1.  //创建对象时向构造函数传参
1.  Student stu("小明", 15, 92.5f);
1.  stu.show();
1.  //创建对象时向构造函数传参
1.  Student *pstu = new Student("李华", 16, 96);
1.  pstu -> show();
1.
1.  return 0;
1.  }

定义了一个构造函数Student(char *, int, float),它的作用是给三个私有成员的值赋值,要想调用该构造函数,就要在创建对象的时候同时传递实参,并且实参有()包围,和普通的函数调用非常类似。 栈上面创建对象的时候实参位于对象名后面,例如Student stu("小明",15,92.5f),在堆上创建对象的时候,实参位于类名后面 构造函数的属性必须是公有的,否则创建对象的时候无法调用,其他情况虽然不会报错但是并没有意义。 构造函数没有返回值,因为没有变量接受返回值,没有return语句 构造函数也能重载。

析构函数

创建对象时系统会自动调用析构函数来做清理工作,比如释放分配的内存,关闭打开的文件,这就是析构函数 我们定义了一个 VLA 类来模拟变长数组,它使用一个构造函数为数组分配内存,这些内存在数组被销毁后不会自动释放,所以非常有必要再添加一个析构函数,专门用来释放已经分配的内存。请看下面的完整示例

1.  #include <iostream>
1.  u[sin](http://c.biancheng.net/ref/sin.html)g namespace std;
1.
1.  class VLA{
1.  public:
1.  VLA(int len); //构造函数
1.  ~VLA(); //析构函数
1.  public:
1.  void input(); //从控制台输入数组元素
1.  void show(); //显示数组元素
1.  private:
1.  int *at(int i); //获取第i个元素的[指针](http://c.biancheng.net/c/80/)
1.  private:
1.  const int m_len; //数组长度
1.  int *m_arr; //数组指针
1.  int *m_p; //指向数组第i个元素的指针
1.  };
1.
1.  VLA::VLA(int len): m_len(len){ //使用初始化列表来给 m_len 赋值
1.  if(len > 0){ m_arr = new int[len]; /*分配内存*/ }
1.  else{ m_arr = NULL; }
1.  }
1.  VLA::~VLA(){
1.  delete[] m_arr; //释放内存
1.  }
1.  void VLA::input(){
1.  for(int i=0; m_p=at(i); i++){ cin>>*at(i); }
1.  }
1.  void VLA::show(){
1.  for(int i=0; m_p=at(i); i++){
1.  if(i == m_len - 1){ cout<<*at(i)<<endl; }
1.  else{ cout<<*at(i)<<", "; }
1.  }
1.  }
1.  int * VLA::at(int i){
1.  if(!m_arr || i<0 || i>=m_len){ return NULL; }
1.  else{ return m_arr + i; }
1.  }
1.
1.  int main(){
1.  //创建一个有n个元素的数组(对象)
1.  int n;
1.  cout<<"Input array length: ";
1.  cin>>n;
1.  VLA *parr = new VLA(n);
1.  //输入数组元素
1.  cout<<"Input "<<n<<" numbers: ";
1.  parr -> input();
1.  //输出数组元素
1.  cout<<"Elements: ";
1.  parr -> show();
1.  //删除数组(对象)
1.  delete parr;
1.
1.  return 0;
1.  }

VLA就是VLA的析构函数,唯一作用就是删除释放后已经分配的内存, 析构函数用加类名来命名,本来~是不允许出现的但是这里是一个特例,目的是与构造函数加以区分 C++中new和delete分别用来分配和和释放内存,它们与C语言中malloc()和free不同,但是new会分配内存会调用构造函数,用delete时调用析构函数。

析构函数的执行时机

析构函数在对象被销毁后使用,而对象的销毁时机与它所在的内存区域有关 在所有函数之外创建的对象是全局对象,和全局变量类似,位于全局数据区,程序在结束执行时会调用这些对象的析构函数。 在函数内部创建的对象是局部对象,在函数调用完成后进行销毁,new 创建的对象位于堆区,通过 delete 删除时才会调用析构函数;如果没有 delete,析构函数就不会被执行。

拷贝构造函数

只有单个形式参数,该形参是本类类型对象的引用,用已经存在的类型对象创建新对象时由编译器自动调用

  • 拷贝构造函数是构造函数的一个重载形式
  • 拷贝构造函数的参数只有一个而且必须使用引用传参,使用传值传参会引发无穷递归调用
  • 若未定义,那么系统会生成默认的拷贝构造函数