page contents

C++新手入门,构造函数详解

在C++中,有一种特殊的成员函数,它的...

在C++中,有一种特殊的成员函数,它的名字和类名相同,没有返回值,不需要用户显式调用(用户也不能调用),而是在创建对象时自动执行。这种特殊的成员函数就是构造函数(Constructor)。

在《C++类成员的访问权限以及类的封装》一篇中,我们通过成员函数 setname()、setage()、setscore() 分别为成员变量 name、age、score 赋值,这样做虽然有效,但显得有点麻烦。有了构造函数,我们就可以简化这项工作,在创建对象的同时为成员变量赋值,请看下面的代码(示例1):

  1. #include <iostream>

  2. using namespace std;

  3. class Student{

  4. private:

  5. char *m_name;

  6. int m_age;

  7. float m_score;

  8. public:

  9. //声明构造函数

  10. Student(char *name, int age, float score);

  11. //声明普通成员函数

  12. void show();

  13. };

  14. //定义构造函数

  15. Student::Student(char *name, int age, float score){

  16. m_name = name;

  17. m_age = age;

  18. m_score = score;

  19. }

  20. //定义普通成员函数

  21. void Student::show(){

  22. cout<<m_name<<"的年龄是"<<m_age<<",成绩是"<<m_score<<endl;

  23. }

  24. int main(){

  25. //创建对象时向构造函数传参

  26. Student stu("小明", 15, 92.5f);

  27. stu.show();

  28. //创建对象时向构造函数传参

  29. Student *pstu = new Student("李华", 16, 96);

  30. pstu -> show();

  31. return 0;

  32. }

运行结果:
小明的年龄是15,成绩是92.5
李华的年龄是16,成绩是96

该例在 Student 类中定义了一个构造函数Student(char *, int, float),它的作用是给三个 private 属性的成员变量赋值。要想调用该构造函数,就得在创建对象的同时传递实参,并且实参由( )包围,和普通的函数调用非常类似。

在栈上创建对象时,实参位于对象名后面,例如Student stu("小明", 15, 92.5f);在堆上创建对象时,实参位于类名后面,例如new Student("李华", 16, 96)。

构造函数必须是 public 属性的,否则创建对象时无法调用。当然,设置为 private、protected 属性也不会报错,但是没有意义。

构造函数没有返回值,因为没有变量来接收返回值,即使有也毫无用处,这意味着:

  • 不管是声明还是定义,函数名前面都不能出现返回值类型,即使是 void 也不允许;

  • 函数体中不能有 return 语句。


构造函数的重载


和普通成员函数一样,构造函数是允许重载的。一个类可以有多个重载的构造函数,创建对象时根据传递的实参来判断调用哪一个构造函数。

构造函数的调用是强制性的,一旦在类中定义了构造函数,那么创建对象时就一定要调用,不调用是错误的。如果有多个重载的构造函数,那么创建对象时提供的实参必须和其中的一个构造函数匹配;反过来说,创建对象时只有一个构造函数会被调用。

对示例1中的代码,如果写作Student stu或者new Student就是错误的,因为类中包含了构造函数,而创建对象时却没有调用。

更改示例1的代码,再添加一个构造函数(示例2):

  1. #include <iostream>

  2. using namespace std;

  3. class Student{

  4. private:

  5. char *m_name;

  6. int m_age;

  7. float m_score;

  8. public:

  9. Student();

  10. Student(char *name, int age, float score);

  11. void setname(char *name);

  12. void setage(int age);

  13. void setscore(float score);

  14. void show();

  15. };

  16. Student::Student(){

  17. m_name = NULL;

  18. m_age = 0;

  19. m_score = 0.0;

  20. }

  21. Student::Student(char *name, int age, float score){

  22. m_name = name;

  23. m_age = age;

  24. m_score = score;

  25. }

  26. void Student::setname(char *name){

  27. m_name = name;

  28. }

  29. void Student::setage(int age){

  30. m_age = age;

  31. }

  32. void Student::setscore(float score){

  33. m_score = score;

  34. }

  35. void Student::show(){

  36. if(m_name == NULL || m_age <= 0){

  37. cout<<"成员变量还未初始化"<<endl;

  38. }else{

  39. cout<<m_name<<"的年龄是"<<m_age<<",成绩是"<<m_score<<endl;

  40. }

  41. }

  42. int main(){

  43. //调用构造函数 Student(char *, int, float)

  44. Student stu("小明", 15, 92.5f);

  45. stu.show();

  46. //调用构造函数 Student()

  47. Student *pstu = new Student();

  48. pstu -> show();

  49. pstu -> setname("李华");

  50. pstu -> setage(16);

  51. pstu -> setscore(96);

  52. pstu -> show();

  53. return 0;

  54. }

运行结果:
小明的年龄是15,成绩是92.5
成员变量还未初始化
李华的年龄是16,成绩是96

构造函数Student(char *, int, float)为各个成员变量赋值,构造函数Student()将各个成员变量的值设置为空,它们是重载关系。根据Student()创建对象时不会赋予成员变量有效值,所以还要调用成员函数 setname()、setage()、setscore() 来给它们重新赋值。

构造函数在实际开发中会大量使用,它往往用来做一些初始化工作,例如对成员变量赋值、预先打开文件等。


默认构造函数


如果用户自己没有定义构造函数,那么编译器会自动生成一个默认的构造函数,只是这个构造函数的函数体是空的,也没有形参,也不执行任何操作。比如上面的 Student 类,默认生成的构造函数如下:


Student(){}


一个类必须有构造函数,要么用户自己定义,要么编译器自动生成。一旦用户自己定义了构造函数,不管有几个,也不管形参如何,编译器都不再自动生成。在示例1中,Student 类已经有了一个构造函数Student(char *, int, float),也就是我们自己定义的,编译器不会再额外添加构造函数Student(),在示例2中我们才手动添加了该构造函数。


实际上编译器只有在必要的时候才会生成默认构造函数,而且它的函数体一般不为空。默认构造函数的目的是帮助编译器做初始化工作,而不是帮助程序员。这是C++的内部实现机制,这里不再深究,初学者可以按照上面说的“一定有一个空函数体的默认构造函数”来理解。


最后需要注意的一点是,调用没有参数的构造函数也可以省略括号。对于示例2的代码,在栈上创建对象可以写作Student stu()或Student stu,在堆上创建对象可以写作Student *pstu = new Student()或Student *pstu = new Student,它们都会调用构造函数 Student()。

以前我们就是这样做的,创建对象时都没有写括号,其实是调用了默认的构造函数。

attachments-2021-03-O19wkt84605ecf7c3dcc3.jpg

  • 发表于 2021-03-27 14:23
  • 阅读 ( 713 )
  • 分类:C/C++开发

0 条评论

请先 登录 后评论
小柒
小柒

1478 篇文章

作家榜 »

  1. 轩辕小不懂 2403 文章
  2. 小柒 1478 文章
  3. Pack 1135 文章
  4. Nen 576 文章
  5. 王昭君 209 文章
  6. 文双 71 文章
  7. 小威 64 文章
  8. Cara 36 文章