0
  • 聊天消息
  • 系统消息
  • 评论与回复
登录后你可以
  • 下载海量资料
  • 学习在线课程
  • 观看技术视频
  • 写文章/发帖/加入社区
会员中心
创作中心

完善资料让更多小伙伴认识你,还能领取20积分哦,立即完善>

3天内不再提示

C++新手容易犯的十个编程错误

STM32嵌入式开发 来源:STM32嵌入式开发 2024-11-15 12:42 次阅读
加入交流群
微信小助手二维码

扫码添加小助手

加入工程师交流群

简单的总结一下C++ 新手容易犯的一些编程错误,给新人们提供一个参考。

1 有些关键字在 cpp 文件中多写了

对于 C++ 类,一些关键字只要写在 .h 中就好,cpp 中就不用再加上了,比如 virtual、static 等关键字,如果在 cpp 中多写,编译器会报错。 比如如下的虚接口与静态成员变量的定义,只要在头文件中声明就可以了。


class shape
{
    virtual Draw();
    //...
    static int nLevel;
}

2 函数参数的默认值写到函数实现中了

带有参数默认值的函数,默认值是加在函数声明处的,函数实现处的参数是不需要带上的。 为了方便查看代码,在函数实现处的参数中,将默认值注释起来。正确的做法是,头文件中有默认值:


BOOL CreateConf( const CString& strConfName, const BOOL bAudio = FALSE );
在函数实现处的参数中不用添加默认值:
BOOL CreateConf( const CString& strConfName, const BOOL bAudio/* = FALSE*/ );
{
    // ......
}

3 在编写类的时候,在类的结尾处忘记添加 ";" 分号了

在类的结尾处忘记添加分号,编译会报错,新人们有可能找了半天也没找出引起编译错误的原因。 其实很简单,在类的结尾处忘记添加分号了。


class Shape
{
    // ...
};

4 只添加了函数声明,没有函数实现

在添加类的函数时,只在类的头文件中添加了函数声明,但在 cpp 中却没有添加函数的实现。 如果其他地方调用到该函数,在编译链接的时候会报unresolved external symbol错误。因为没有实现,所有没有供链接使用的 obj 文件。

5 cpp 文件忘记添加到工程中,导致没有生成供链接使用的 obj 文件

在添加 C++ 类时,我们一般会添加 .h 头文件和一个 .cpp 源文件。结果忘记把 .cpp 文件添加到工程中了,即没有参与编译,没有生成供链接使用的 obj 文件。 如果有代码调用到该 C++ 类的接口,则在编译链接的时候会报unresolved external symbol错误,即链接不到该 C++ 类对应的接口。

6 函数中返回了一个局部变量的地址或者引用

在函数中返回了一个局部变量的地址或者引用,而这个局部变量在函数结束时其生命周期就结束了,内存就被释放了。 当外部访问到该变量的内存,会触发内存访问违例的异常,因为该变量的内存已经释放了。比如如下的错误代码:


char* GetResult()
{
    char chResult[100] = { 0 };


    // ......


    return chResult;
}

7 忘记将父类中的接口声明 virtual 函数,导致多态没有生效

代码中本来要借助于 C++ 多态的虚函数调用,调用子类实现的接口,结果忘记在父类中将对应的接口声明为 virtual,导致没有调用到子类实现的函数。 一定要记住,要实现多态下的函数调用,父类的相关接口必须声明为 virtual。


class Shape()
{
    // ...


    virtual void Draw();


    // ...
}

8 该使用双指针的地方,却使用了单指针

有时我们需要调用一个接口去获取某些数据,接口中将数据拷贝到传入的参数对应的内存中,此时设计参数时会传入指针或引用。 我们在调用GetData 之前定义了结构体指针p,并 new 出了对应的结构体对象内存,应该在定义 GetData 接口时应该使用双指针(指针的指针)的,结果错写成了单指针。 有问题的代码如下:


struct CodecInfo     // 编码信息
{
    int nFrameRate;


    // ...
}


CodecInfo* pInfo = new CodecInfo;


GetAudioCodecPtr()->GetCodecInfo(pInfo);   // 调用AudioCodec::GetCodecInfo获取编码信息


AudioCodec::GetCodecInfo( CodecInfo* pInfo)  // 此处的参数不应该使用单指针
{
    memcpy(pInfo, m_codecInfo, sizeof(CodecInfo));
}
上面中的AudioCodec::GetCodecInfo接口的参数不应该为单指针,应该用双指针,修改后的代码应该如下:

AudioCodec::GetCodecInfo( CodecInfo** pInfo)  // 此处的参数类型使用双指针
{
    memcpy(*pInfo, m_codecInfo, sizeof(CodecInfo));
}

9 发布 exe 程序时,忘记将 exe 依赖的 C 运行时库和 MFC 库带上

比如新人用 VS-MFC 库编写一个测试用的工具软件,结果在发布 release 版本程序时,没有将程序依赖的 C 运行时库带上,导致该工具软件在某些电脑中启动报错,提示找不到 C 运行时库: 因为程序中依赖了动态版本的运行时库和 MFC 库,在发布程序时要将这些库带上。有些系统中没有这些库,程序启动时就会报找不到库,就会启动失败。

10 应该使用深拷贝,却使用了浅拷贝

本来应该要进行深拷贝的,却使用了浅拷贝(直接赋值),导致另个不同生命周期的 C++ 对象指向了同一块内存,一个对象将内存释放后,另一个对象再用到这块内存,就造成了内存访问违例,产生异常。 有个经典的 C++ 笔试题,让我们实现 String 类的相关函数,其主要目的就是用来考察对深拷贝与浅拷贝的理解的。题目中给出 String类的声明:


class String{
public:
    String();
    String(const String & str);
    String(const char* str);
    String& operator=(String str);
    char* c_str() const;
    ~String();
    int size() const;
private:
    char* data;
};
让写出上述几个函数的内部实现。这些函数的实现代码如下:

//普通构造函数  
String::String(const char *str)
{
  if (str == NULL)
  {
    m_data = new char[1];// 得分点:对空字符串自动申请存放结束标志'�'的,加分点:对m_data加NULL判断  
    *m_data = '�';
  }
  else
  {
    int length = strlen(str);
    m_data = new char[length + 1];// 若能加 NULL 判断则更好
    strcpy(m_data, str);
  }
}
 
 
// String的析构函数  
String::~String(void)
{
  delete[] m_data; // 或delete m_data;  
}
 
 
//拷贝构造函数  
String::String(const String &other)// 得分点:输入参数为const型  
{     
  int length = strlen(other.m_data);
  m_data = new char[length + 1];// 若能加 NULL 判断则更好  
  strcpy(m_data, other.m_data);
}
 
 
//赋值函数  
String & String::operator = (const String &other) // 得分点:输入参数为const型  
{
  if (this == &other)//得分点:检查自赋值  
    return *this; 
  if (m_data)
      delete[] m_data;//得分点:释放原有的内存资源  
  int length = strlen(other.m_data);
  m_data = new char[length + 1];//加分点:对m_data加NULL判断  
  strcpy(m_data, other.m_data);
  return *this;//得分点:返回本对象的引用    
}

声明:本文内容及配图由入驻作者撰写或者入驻合作网站授权转载。文章观点仅代表作者本人,不代表电子发烧友网立场。文章及其配图仅供工程师学习之用,如有内容侵权或者其他违规问题,请联系本站处理。 举报投诉
  • 编程
    +关注

    关注

    90

    文章

    3723

    浏览量

    97432
  • C++
    C++
    +关注

    关注

    22

    文章

    2129

    浏览量

    77360

原文标题:C++:10种新手易犯错误

文章出处:【微信号:c-stm32,微信公众号:STM32嵌入式开发】欢迎添加关注!文章转载请注明出处。

收藏 人收藏
加入交流群
微信小助手二维码

扫码添加小助手

加入工程师交流群

    评论

    相关推荐
    热点推荐

    Libevent C++高并发网络编程 | 完结

     在2026年的技术版图中,尽管高级语言和AI辅助编程已经接管了大部分业务逻辑的构建,但在高并发、低延迟的核心网络基础设施领域,C++与Libevent的结合依然稳如磐石。它们构成了数字世界
    的头像 发表于 04-20 15:50 484次阅读

    信号完整性仿真中容易的几个错误

    说出来你可能不信,很多工程师拿着漂亮的仿真报告,实物一测试,问题全出来了。返工、延期、挨骂,样样都逃不掉。
    的头像 发表于 04-20 10:17 495次阅读
    信号完整性仿真中<b class='flag-5'>容易</b><b class='flag-5'>犯</b>的几个<b class='flag-5'>错误</b>

    C++与lua联合编程

    手工业”。然而,这两种内存管理机制截然不同的语言,如何在一进程内进行高效的数据交换,一直是企业级开发中的痛点。(看讠果aixuetang。xyz) 从经济学的视角来审视,夏曹俊老师《C++ 脚本编程
    发表于 04-19 16:27

    Linux新手最常踩的10命令坑介绍

    从事运维工作余年,带过不少新人,发现有些命令错误几乎是每个Linux使用者都曾经遇到过的。这些错误轻则导致操作失败、浪费时间,重则引发数据丢失、服务中断、生产事故。本篇文章结合2026年
    的头像 发表于 04-09 10:11 193次阅读

    keil实现cc++混合编程

    起因项目中使用到一开源的模拟IIC的库,封装的比较好,但是是使用c++写的。于是将其移植到自己的项目中,主要有以下三步操作: 在工程选项中 C/C++中去掉勾选
    发表于 01-26 08:58

    汽车网络安全开发语言选型指南:C/C++/Rust/Java等主流语言对比+Perforce QAC/Klocwork工具支持

    汽车网络安全如何选编程语言?CC++、Rust、Java……谁更适合AUTOSAR、ISO/SAE 21434?一文了解8种主流语言的优劣与适用场景,以及Perforce QAC/Klocwork对MISRA、CERT等规范的
    的头像 发表于 12-26 11:13 650次阅读
    汽车网络安全开发语言选型指南:<b class='flag-5'>C</b>/<b class='flag-5'>C++</b>/Rust/Java等主流语言对比+Perforce QAC/Klocwork工具支持

    大常见的芯片烧录错误,第5几乎人人都遇到过

    本文聚焦芯片烧录环节,盘点了大常见且易被忽视的错误,包括轻视编程器选择、盲目使用新算法、忽视电源接地质量、芯片接触不良、跳过空白检查与校验、忽略环境温度影响等。强调可靠烧录并非孤立动作,而是涵盖物料、设备、流程、环境的质量控制
    的头像 发表于 12-25 14:49 621次阅读
    <b class='flag-5'>十</b>大常见的芯片烧录<b class='flag-5'>错误</b>,第5<b class='flag-5'>个</b>几乎人人都遇到过

    C语言与C++的区别及联系

    C语言和C++到底是什么关系? 首先C++C语言本来就是两种不同的编程语言,但C++确实是对
    发表于 12-24 07:23

    CC++之间的联系

    控制能力,这一点与C语言相似,使得它们在系统编程、嵌入式系统等领域都得到广泛应用。 3、发展历程: C++正是在C语言的基础上逐步发展起来的,C
    发表于 12-11 06:51

    C语言和C++之间的区别是什么

    ,尤其是在涉及到类型转换时,会尽量防止隐式的、可能导致问题的类型转换。 相比之下,C语言允许更多的灵活性,但也更容易产生类型相关的运行时错误,因为其类型检查不如C++严格。 3、函数
    发表于 12-11 06:23

    C++程序异常的处理机制

    1、什么是异常处理? 有经验的朋友应该知道,在正常的CC++编程过程中难免会碰到程序不按照原本设计运行的情况。 最常见的有除法分母为零,数组越界,内存分配失效、打开相应文件失败等等。 一
    发表于 12-02 07:12

    技能+1!如何在树莓派上使用C++控制GPIO?

    在使用树莓派时,你会发现Python和Scratch是许多任务(包括GPIO编程)中最常用的编程语言。但你知道吗,你也可以使用C++进行GPIO编程,而且这样做还有不少好处。借助Wir
    的头像 发表于 08-06 15:33 4488次阅读
    技能+1!如何在树莓派上使用<b class='flag-5'>C++</b>控制GPIO?

    C++ 与 Python:树莓派上哪种语言更优?

    Python是树莓派上的首选编程语言,我们的大部分教程都使用它。然而,C++在物联网项目中同样广受欢迎且功能强大。那么,在树莓派项目中选择哪种语言更合适呢?Python因其简洁性、丰富的库和资源而被
    的头像 发表于 07-24 15:32 1104次阅读
    <b class='flag-5'>C++</b> 与 Python:树莓派上哪种语言更优?

    避雷!树莓派初学者常犯的5错误

    如果你刚刚入手树莓派,你就会知道它潜力无穷,几乎能实现你想到的任何功能。然而,这种自由也让你可能在不知不觉中做出对系统有害的操作。在本文中,我将介绍要避免哪些错误。初学者最常犯的错误包括:损坏SD
    的头像 发表于 07-22 17:16 1562次阅读
    避雷!树莓派初学者常犯的5<b class='flag-5'>个</b><b class='flag-5'>错误</b>!

    使用英特尔® NPU 插件C++运行应用程序时出现错误:“std::Runtime_error at memory location”怎么解决?

    使用OpenVINO™工具套件版本 2024.4.0 构建C++应用程序 使用英特尔® NPU 插件运行了 C++ 应用程序 遇到的错误: Microsoft C++ excep
    发表于 06-25 08:01