构造器中的三个小问题

关于构造器中的三个问题验证。

 

问题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++基础与提高》

posted @ 2021-02-01 18:33  bruce628  阅读(64)  评论(0编辑  收藏  举报