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";}}}