当前位置: 首页 > news >正文

C++ 编程问题记录

1.虚函数未给出定义(未声明为纯虚函数或者未加{}):

main.cpp中以下代码段只有声明,没有实现

virtual void Speak();

报错如下(未定义引用):

shaoyoulu@shaoyoulu:~/Code/C++/C++32/C++/review/day4/pure$ g++ pure.cpp -o pure
pure.cpp: In function ‘void test01()’:
pure.cpp:50:31: warning: ISO C++ forbids converting a string constant to ‘char*’ [-Wwrite-strings]50 |     Animal * animal = new Cat("tom");|                               ^~~~~
/usr/bin/ld: /tmp/cc3cdZdX.o: warning: relocation against `_ZTV6Animal' in read-only section `.text._ZN6AnimalD2Ev[_ZN6AnimalD5Ev]'
/usr/bin/ld: /tmp/cc3cdZdX.o: in function `Animal::Animal()':
pure.cpp:(.text._ZN6AnimalC2Ev[_ZN6AnimalC5Ev]+0x13): undefined reference to `vtable for Animal'
/usr/bin/ld: /tmp/cc3cdZdX.o: in function `Animal::~Animal()':
pure.cpp:(.text._ZN6AnimalD2Ev[_ZN6AnimalD5Ev]+0x13): undefined reference to `vtable for Animal'
/usr/bin/ld: /tmp/cc3cdZdX.o:(.data.rel.ro._ZTI3Cat[_ZTI3Cat]+0x10): undefined reference to `typeinfo for Animal'
/usr/bin/ld: warning: creating DT_TEXTREL in a PIE
collect2: error: ld returned 1 exit status

应修改为:

virtual void Speak(){}

或者:

virtual void Speak() = 0

main.cpp

#include <cstring>class Animal{public:Animal(){std::cout<<"call Animal constructor.\n";}~Animal(){std::cout<<"call Animal destructor.\n";}virtual void Speak();
};class Cat:public Animal{public:Cat(char * name){std::cout<<"call Cat constructor.\n";m_Name = new char[strlen(name) + 1];strcpy(m_Name,name);}virtual void Speak(){std::cout<<"cat speaking\n";}~Cat(){std::cout<<"call Cat destructor.\n";if(m_Name != NULL){delete [] m_Name;m_Name = NULL;}}public:char * m_Name;
};void test01()
{Animal * animal = new Cat("tom");}void test02()
{}void test03()
{}void test04()
{}int main()
{test01();test02();  test03();test04();return EXIT_SUCCESS;
}码片

2.对父类析构函数的引用

main.cpp中的析构函数修改为纯虚函数后,并且未给出定义:

#include <cstring>class Animal{public:Animal(){std::cout<<"call Animal constructor.\n";}// virtual ~Animal()// {//     std::cout<<"call Animal destructor.\n";// }virtual ~Animal() = 0;virtual void Speak(){}
};class Cat:public Animal{public:Cat(char * name){std::cout<<"call Cat constructor.\n";m_Name = new char[strlen(name) + 1];strcpy(m_Name,name);}virtual void Speak(){std::cout<<"cat speaking\n";}~Cat(){std::cout<<"call Cat destructor.\n";if(m_Name != NULL){delete [] m_Name;m_Name = NULL;}}public:char * m_Name;
};void test01()
{Animal * animal = new Cat{"tom"};animal->Speak();delete animal;
}void test02()
{}void test03()
{}void test04()
{}int main()
{test01();test02();  test03();test04();return EXIT_SUCCESS;
}

报错如下:

shaoyoulu@shaoyoulu:~/Code/C++/C++32/C++/review/day4/pure$ g++ pure.cpp -o pure
pure.cpp: In function ‘void test01()’:
pure.cpp:51:31: warning: ISO C++ forbids converting a string constant to ‘char*’ [-Wwrite-strings]51 |     Animal * animal = new Cat{"tom"};|                               ^~~~~
/usr/bin/ld: /tmp/ccAio8Ka.o: in function `Cat::Cat(char*)':
pure.cpp:(.text._ZN3CatC2EPc[_ZN3CatC5EPc]+0x93): undefined reference to `Animal::~Animal()'
/usr/bin/ld: /tmp/ccAio8Ka.o: in function `Cat::~Cat()':
pure.cpp:(.text._ZN3CatD2Ev[_ZN3CatD5Ev]+0x75): undefined reference to `Animal::~Animal()'
collect2: error: ld returned 1 exit status

其中提到,在Cat::Cat(char*)中有对Animal::~Animal()的undefined reference
这是什么?
子类的构造函数为什么会调用父类的析构?
是真的有子类的构造对父类的析构函数的调用?还是未给出存虚函数的定义导致的一些错误而并非存在这样的调用?

3.对于类中引用成员,必须用初始化列表进行初始化

main.cpp中使用的初始化的方式为:

PC(CPU & _cpu,GPU & _gpu){cpu = _cpu;gpu = _gpu;}

这两个成员都是引用对象

This warning means you are not initializing reference members (CPU & cpu;, GPU & gpu;) in the member initializer list of the PC constructor.
Reference members must be initialized in the initializer list, not inside the constructor body.

必须使用初始化列表进行初始化

main.cpp

#include <iostream>class CPU{public:virtual void Compute() = 0;
};class GPU{public:virtual void Render() = 0;
};class PC{
public:PC(CPU & _cpu,GPU & _gpu){cpu = _cpu;gpu = _gpu;}void Run(){cpu.Compute();gpu.Render();}public:CPU & cpu;GPU & gpu;
};class IntelCPU:public CPU{public:virtual void Compute(){std::cout<<"Intel CPU is computing...\n";}
};class AMDCPU:public CPU{public:virtual void Compute(){std::cout<<"AMD cpu is computing...\n";}
};class AMDGPU:public GPU{public:virtual void Render(){std::cout<<"AMD GPU is rendering...\n";}
};
class NVIDIAGPU:public GPU{public:virtual void Render(){std::cout<<"NVIDIA GPU is rendering...\n";}
};void test01()
{}int main()
{test01();return EXIT_SUCCESS;
}

4.用临时对象初始化带来的问题

main.cpp中使用如下方式进行初始化:

PC mypc(IntelCPU(),AMDGPU());

这会带来问题:

aoyoulu@shaoyoulu:~/Code/C++/C++32/C++/review/day4/assembly$ g++ assemble.cpp -o assemble
assemble.cpp: In function ‘void test01()’:
assemble.cpp:71:12: warning: parentheses were disambiguated as a function declaration [-Wvexing-parse]71 |     PC mypc(IntelCPU(),AMDGPU());|            ^~~~~~~~~~~~~~~~~~~~~
assemble.cpp:71:12: note: replace parentheses with braces to declare a variable71 |     PC mypc(IntelCPU(),AMDGPU());|            ^~~~~~~~~~~~~~~~~~~~~|            -|            {                   -|                                }
shaoyoulu@shaoyoulu:~/Code/C++/C++32/C++/review/day4/assembly$ 

该语句被消歧为函数声明 – disambiguated(消歧) as a function

…is interpreted by the compiler as a function declaration, not as an object definition.
Do not use temporary objects for reference members.
Always create objects first, then pass them to the constructor.

正确做法:

void test01()
{IntelCPU intel;AMDGPU amdGpu;PC mypc(intel, amdGpu);mypc.Run();
}

main.cpp

#include <iostream>class CPU{public:virtual void Compute() = 0;
};class GPU{public:virtual void Render() = 0;
};class PC{
public:PC(CPU & _cpu,GPU & _gpu):cpu(_cpu),gpu(_gpu){// cpu = _cpu;// gpu = _gpu;}void Run(){cpu.Compute();gpu.Render();}public:CPU & cpu;GPU & gpu;
};class IntelCPU:public CPU{public:virtual void Compute(){std::cout<<"Intel CPU is computing...\n";}
};class AMDCPU:public CPU{public:virtual void Compute(){std::cout<<"AMD cpu is computing...\n";}
};class AMDGPU:public GPU{public:virtual void Render(){std::cout<<"AMD GPU is rendering...\n";}
};
class NVIDIAGPU:public GPU{public:virtual void Render(){std::cout<<"NVIDIA GPU is rendering...\n";}
};void test01()
{PC mypc(IntelCPU(),AMDGPU());
}void test02()
{}void test03()
{}void test04()
{}int main()
{test01();test02();  test03();test04();return EXIT_SUCCESS;
}

5.'a' >> int num ----> num = 0

对int类型输入非int类型数据会置0

对如下代码调试可以发现

    int num = 100;std::cin>>num;

当输入字符‘a’等内容或者字符串等数据时,num将会被赋值为0

如下main.cpp代码中,test01()输入非数字会导致程序结束,因为判断中包含 为0通过:

if(num>=0 && num<= 10)

而test02中则不会发生输入字符导致程序结束:

 if(num>0 && num <10)

这是由于对num的输入错误时,会将num强制赋值为0引起的。

main.cpp

#include <iostream>
#include <limits>void test01()
{std::cout<<"input num:\n";// int num = 0xffffffff;int num = 100;while(1){std::cin>>num;if(num>=0 && num<= 10){std::cout<<"you num:"<<num<<std::endl;break;}else{std::cout<<"input error\n";}std::cout<<"cin.fail() = "<<std::cin.fail()<<std::endl;if(std::cin.fail()){std::cin.clear();// std::cin.ignore();std::cin.sync();std::cin.ignore(std::numeric_limits<std::streamsize>::max(), '\n');}// std::cout<<"input error"<<std::endl;}}void test02()
{std::cout<<"input a num(0~10):\n";int num;while(1){std::cin >>num;if(num>0 && num <10){std::cout<<"your num is "<<num<<std::endl;break;}else{std::cout<<"input error.\n";}// if flag = 0 -- normal// flag = 1-- buffer --abnormalstd::cout<<"cin.fail() = "<<std::cin.fail()<<std::endl;std::cin.clear();std::cin.sync();std::cin.ignore();}
}void test03()
{}void test04()
{}int main()
{test01();// test02();test03();test04();return EXIT_SUCCESS;
}

可以使用先判断加continue解决问题

#include <limits>void test01() {std::cout << "input num:\n";int num = 0;  // Initialize numwhile (1) {std::cin >> num;if (std::cin.fail()) {std::cin.clear(); // Clear fail statestd::cin.ignore(std::numeric_limits<std::streamsize>::max(), '\n'); // Discard invalid inputstd::cout << "Invalid input. Please enter a number between 0 and 10.\n";continue; // Skip the rest of the loop and prompt again}if (num >= 0 && num <= 10) {std::cout << "you num:" << num << std::endl;break; // Exit the loop if valid input is within range} else {std::cout << "input error\n";}}}
http://www.lryc.cn/news/604131.html

相关文章:

  • 对象的创建过程
  • Linux学习--C语言(指针4、结构体)
  • 【Spring】日志级别的分类和使用
  • Qt小技巧 QStandardPaths详解
  • C语言14-指针4-二维数组传参、指针数组传参、viod*指针
  • JAVA_TWENTY—ONE_单元测试+注解+反射
  • 在 Cloudflare 平台上完整部署 GitHub 项目 MoonTV 实现免费追剧流程
  • vite + chalk打印输出彩色命令行
  • 并查集介绍及典型应用和编程题
  • Python爬虫01_Requests第一血获取响应数据
  • __getattr__和 __getattribute__ 的用法
  • Docker学习相关视频笔记(二)
  • linux内核报错汇编分析
  • 云原生周刊:2025年的服务网格
  • JSON-RPC 2.0 规范
  • fastjson反序列化时_id的处理
  • WebRTC 2025全解析:从技术原理到商业落地
  • MC0241防火墙
  • 16大工程项目管理系统对比:开源与付费版本
  • 牛客网之华为机试题:密码验证程序
  • python-网络编程
  • Qt 移动应用性能优化策略
  • 板凳-------Mysql cookbook学习 (十二--------7)
  • Android User版本默认用test-keys,如何改用release-keys
  • 北方公司面试记录
  • 前端数据库:IndexedDB从基础到高级使用指南
  • 基于Prophet、滑动平均、加权平均的地铁客流量预测与可视化系统的设计与实现
  • Java【代码 17】httpclient PoolingHttpClientConnectionManager 连接池使用举例
  • 无穿戴动作捕捉技术:驱动历史活化、乐园叙事与教育沉浸的文旅利器
  • [Linux入门] Linux 部署本地 APT 仓库及 NFS 共享服务全攻略