构造器中的三个小问题
关于构造器中的三个问题验证。
问题1:默认无参空构造器的疑惑
先上代码,类中有两个构造函数,一个是无参构造器,一个是带参构造器,形成重载。
1 #include <iostream> 2 3 using namespace std; 4 5 class Stack 6 { 7 public: 8 /* 无参构造器 */ 9 Stack() 10 { 11 top = 0; 12 m_size = 1024; 13 space = new int[1024]{0}; 14 } 15 /* 带参的构造器*/ 16 Stack(int size) 17 :top(0), m_size(size), space(new int[size]{0}) 18 { 19 } 20 21 bool isFull() 22 { 23 return top == m_size; 24 } 25 26 bool isEmpty() 27 { 28 return top == 0; 29 } 30 31 void push(int data) 32 { 33 space[top++] = data; 34 } 35 36 int pop() 37 { 38 return space[--top]; 39 } 40 protected: 41 int top; 42 int m_size; 43 int *space; 44 }; 45 46 int main() 47 { 48 Stack s; 49 for(int i = 0; i < 10 && !s.isFull(); ++i) 50 { 51 s.push(i); 52 } 53 for(int i = 0; i < 10; ++i) 54 { 55 cout<<s.pop()<<" "; 56 } 57 cout<<endl; 58 59 cout<<"=========="<<endl; 60 Stack s2(20); 61 for(int i = 0; i < 30 && !s.isFull(); ++i) 62 { 63 s.push(i); 64 } 65 for(int i = 0; i < 20; ++i) 66 { 67 cout<<s.pop()<<" "; 68 } 69 cout<<endl; 70 71 return 0; 72 }
测试1:只注释带参的构造器
现象:第48行代码能正常编译,找到了无参构造器,对象s可实例化。第60行代码编译不过,因来未找到对应的带参的构造器,对象s2无法实例化。
这个比较好理解。
测试2:同时注释无参的构造器和带参的构造器
现象:第48行代码能正常编译。第60行代码提示编译不过,没有找到匹配的构造器。
问题:两个构造器,其中一个是无参构造器,两个都被注释了,为什么第48行代码能编译通过,不报错呢?哪里在来的无参构造器呢?天外飞来的无参构造器?
测试3:仅注释无参的构造器
现象:第48行代码报错,提示未找到匹配的构造器。第60行代码编译通过。
有带参的构造器,第60行代码能编译过去,这个比较好理解。但与测试2对比也会令人有点疑惑,不是说好的有“天外飞来的无参构造器”吗?咋这时又不灵了呢?
说明:系统提供默认的空体构造体,一经自实现默认的将不复存在。
当没有自实现构造器的时候,系统会提供默认的构造器(如测试2)。一旦自己定义了构造器,默认的构造器将不存在了(如测试3)。
提示:测试2中虽然编译通过了, 但是运行结果是未定义的。
所以, 咱们在实现重载或者默认参数的时候,需要将默认无参构造器,纳入其中。
问题2:Stack s2()是个啥?
第1和2行均是表示申明了一个对象,前者无参,后者带参,这个好理解。加了第3行,初看起来,感觉怪怪的,这是个啥呢?
1 Stack s; 2 Stack s2(20); 3 Stack s3();
咱运行一把,也没有报错啥的。
有的朋友估计已经想到了,这是个函数申明。Stack表示类类型,s3表示函数名,函数名后跟括号。感觉是学的越多,越糊涂呀(哭笑)。
问题3:类成员初始化的顺序
类成员初始化的顺序与什么有关呢?
代码如下,在G++ 4.8.5版本中,运行结果是5;
1 #include <iostream> 2 #include <string> 3 4 using namespace std; 5 6 class A 7 { 8 public: 9 A(string str) 10 :m_name(str), m_len(m_name.length()) 11 {} 12 13 void dis() 14 { 15 cout<<m_len<<endl; 16 } 17 protected: 18 string m_name; 19 int m_len; 20 }; 21 22 int main() 23 { 24 A a("china"); 25 a.dis(); 26 27 return 0; 28 }
测试1:调整列表初始化的顺序,将第10行代码调整为如下,运行结果仍是5
1 m_len(m_name.length()),m_name(str)
测试2:调整声明的顺序,调换第18行与19行的顺序,再观察运行结果。
显示
Segmentation fault
在列表初始化m_len时,需要m_name这个类成员,但是m_name还未初始化,因此此时出现了错误。不同的平台中可能会得到一些不同的结果。
说明:类成员初始化的顺序与初始化参数列表的顺序无关,与其声明的顺序有关。
注:
主要开发工具:QT5.12,有时会用到G++;
操作系统:Win10;
参考书籍:王桂林《C++基础与提高》