文章详情

短信预约-IT技能 免费直播动态提醒

请输入下面的图形验证码

提交验证

短信预约提醒成功

C++构造函数常见的坑有哪些

2023-06-22 07:29

关注

今天就跟大家聊聊有关C++构造函数常见的坑有哪些,可能很多人都不太了解,为了让大家更加了解,小编给大家总结了以下内容,希望大家根据这篇文章可以有所收获。

某一天我们接到了一个需求,需要开发一个类似于STLstring的类。

我们很快写好了代码:

#include <iostream>#ifndef STRINGBAD_H_#define STRINGBAD_H_class StringBad {    private:     char *str;     int len;     static int num_strings;    public:     StringBad(const char* s);     StringBad();     ~StringBad();     friend std::ostream & operator << (std::ostream &os, const StringBad & st);};#endif

在这个.h文件当中,我们定义了一个StringBad类,这是C++ Primer当中的一个例子。为什么叫StringBad呢,主要是为了提示,表示这是一个没有完全开发好的demo

这里有一个小细节,我们在类当中定义的是一个char *也就是字符型指针,而非字符型数组。这意味着我们在类声明当中没有为字符串本身分配空间,而是在构造函数当中使用new来完成的,避免了预先定义字符串的长度。

其次num_strings是一个静态成员,也就是说无论创建了多少对象,它都只会保存一份。类的所有成员共享同一个静态变量。

接下来我们来看一下它的实现:

#include <cstring>#include "stringbad.h"using std::cout;int StringBad::num_strings = 0;StringBad::StringBad(const char* s) {    len = std::strlen(s);    str = new char[len+1];    std::strcpy(str, s);    num_strings++;    cout << num_strings << ": \"" << str << "\" object created \n";}StringBad::StringBad() {    len = 4;    str = new char[4];    std::strcpy(str, "C++");    num_strings++;    cout << num_strings << ": \"" << str << "\" object created \n";}StringBad::~StringBad() {    cout << "\"" << str << "\" object deleted, ";    --num_strings;    cout << num_strings << " left \n";    delete []str;}std::ostream & operator<<(std::ostream & os, const StringBad &st) {    os << st.str;    return os;}

首先,我们可以注意到第一句就是将num_strings初始化成了0,我们不能在类声明中初始化静态成员变量。因为声明只是描述了如何分配内存,但并不真的分配内存。

所以对于静态类成员,我们可以在类声明之外使用单独的语句进行初始化。因为静态成员变量是单独存储的,并不是对象的一部分。

初始化要在方法文件也就是cpp文件当中,而不是头文件中。因为头文件可能会被引入多次,如果在头文件中初始化将会引起错误。当然也有一种例外,就是加上了const关键字。

从逻辑上看,我们这样实现并没有任何问题,但是当我们执行的时候,就会发现问题很多&hellip;&hellip;

假设我们现在有一个函数:

void callme(StringBad sb) { cout << "    \"" << sb << "\"\n";}

然后我们这么使用:

int main() { StringBad sb("test"); callme(sb); return 0;}

会得到一个奇怪的结果:

C++构造函数常见的坑有哪些

从屏幕可以看到我们的析构函数执行了两次,一次很好理解应该是main函数退出的时候自动执行的,还有一次呢?是什么时候执行的?

答案是执行callme函数的时候执行的,因为callme函数使用了值传递。当callme函数执行结束时,也会调用参数sb的析构函数。

如果我们改成引用传递,就一切正常了:

void callme(StringBad &sb) { cout << "    \"" << sb << "\"\n";}int main() { StringBad sb("test"); callme(sb); return 0;}

C++构造函数常见的坑有哪些

这还没完,我们把代码再改一下,会发现还有问题:

int main() { StringBad sb("test"); StringBad sports("Spinach Leaves Bowl for Dollars"); StringBad sailor = sports; StringBad knot; StringBad st = sb; return 0;}

执行一下,得到:

C++构造函数常见的坑有哪些

会发现又有负数出现了,这是为什么呢?

因为我们执行了StringBad st = sb这样的操作,这个操作并不会调用我们实现的任何一个构造函数。

它等价于:

StringBad st = StringBad(sb);

对应的构造函数原型是:

StringBad(const StringBad&);

当我们用一个对象来初始化另外一个对象的时候,编译器将会自动生成上述的构造函数。这样的构造函数叫做拷贝构造函数,由于我们没有重载拷贝构造函数,因此它不知道要对num_strings变量做处理,也就导致了不一致的发生。

看完上述内容,你们对C++构造函数常见的坑有哪些有进一步的了解吗?如果还想了解更多知识或者相关内容,请关注编程网行业资讯频道,感谢大家的支持。

阅读原文内容投诉

免责声明:

① 本站未注明“稿件来源”的信息均来自网络整理。其文字、图片和音视频稿件的所属权归原作者所有。本站收集整理出于非商业性的教育和科研之目的,并不意味着本站赞同其观点或证实其内容的真实性。仅作为临时的测试数据,供内部测试之用。本站并未授权任何人以任何方式主动获取本站任何信息。

② 本站未注明“稿件来源”的临时测试数据将在测试完成后最终做删除处理。有问题或投稿请发送至: 邮箱/279061341@qq.com QQ/279061341

软考中级精品资料免费领

  • 历年真题答案解析
  • 备考技巧名师总结
  • 高频考点精准押题
  • 2024年上半年信息系统项目管理师第二批次真题及答案解析(完整版)

    难度     801人已做
    查看
  • 【考后总结】2024年5月26日信息系统项目管理师第2批次考情分析

    难度     348人已做
    查看
  • 【考后总结】2024年5月25日信息系统项目管理师第1批次考情分析

    难度     311人已做
    查看
  • 2024年上半年软考高项第一、二批次真题考点汇总(完整版)

    难度     432人已做
    查看
  • 2024年上半年系统架构设计师考试综合知识真题

    难度     220人已做
    查看

相关文章

发现更多好内容

猜你喜欢

AI推送时光机
位置:首页-资讯-后端开发
咦!没有更多了?去看看其它编程学习网 内容吧
首页课程
资料下载
问答资讯