🕵️♀️1. 强制类型转换注意点
C++的格式转化和C语言不同,
- 静态强制类型转换 (
static_cast
)- 动态强制类型转换 (
dynamic_cast
)- 常量强制类型转换 (
const_cast
)- 旧式的 C 风格转换函数
程序示例:
#include <iostream> using namespace std; class Base { public: virtual void foo() {} }; class Derived : public Base { // ... }; int main() { // 静态强制类型转换 double myDouble = 3.14; int myInt = static_cast<int>(myDouble); cout << "Static Cast: " << myInt << ", Type: " << typeid(myInt).name() << endl; // C语言旧式强制类型转换 double myOldDouble = 4.56; int myOldInt = (int)myOldDouble; cout << "Old-Style Cast: " << myOldInt << ", Type: " << typeid(myOldInt).name() << endl; // 动态强制类型转换 Base* basePtr = new Derived; Derived* derivedPtr = dynamic_cast<Derived*>(basePtr); if (derivedPtr) { cout << "Dynamic Cast: Successful, Type: " << typeid(*derivedPtr).name() << endl; } else { cout << "Dynamic Cast: Failed" << endl; } // 常量强制类型转换,使用 const_cast 移除 const 修饰符 const int myConstInt = 42; int* myMutableInt = const_cast<int*>(&myConstInt); *myMutableInt = 99; cout << "Const Cast: " << *myMutableInt << ", Type: " << typeid(*myMutableInt).name() << endl; return 0; }
🕵️♀️2. 处理字符串注意点
🌐2.1 按行获取字符串 | 字符数组 + 指针问题
🔍2.1.1 C++解决方案
按行获取字符串
- 对于字符数组:cin.getline(ch,MaxSize);
- 对于字符串:getline(cin,str);
两者使用scanf都不加&
/***字符数组***/ //输入方式一 char ch[100] = { 0 }; cin.getline(ch, sizeof(ch)); //输入方式二 char ch2[100] = { 0 }; scanf("%s", ch2);//不加&,而%c需要加& /***字符串***/ //输入方式一 string s1; getline(cin,s1); //输入方式二 string s2[100] = { 0 }; scanf("%s", s2);//不加&,而字符串指针需要加&
指针
- 字符指针:不加&
- 字符串指针:加&
//字符指针 char str[100]="hello"; char *ptr=str;//不是char *ptr= &str; 并且*ptr指向第一个字符元素h //字符串指针 string s1="hello"; string *p1=&s1;//不是string *p1=s1; *p代表整个12字符串 char *p2=&s1[0]; cout<<*p1<<endl;
字符串最后一个字符为'\0'
程序示例:
#include <iostream> using namespace std; int main() { /*字符数组*/ //输入方式一 char ch[100] = { 0 }; cin.getline(ch, sizeof(ch)); //字符指针 char *ptr=ch;//不是char *ptr= &ch; 并且*ptr指向第一个字符元素 for(;*ptr!='\0';ptr++){ cout<<*ptr; } cout<<endl; //输入方式二 char ch2[100] = { 0 }; scanf("%s", ch2);//不加&,而%c需要加& /*字符串*/ //输入方式一 string s1; getline(cin,s1); //字符串指针 string *p1=&s1;//不是string *p1=s1; *p代表整个12字符串 cout<<*p1<<endl; //输入方式二 string s2[100] = { 0 }; scanf("%s", s2);//不加&,而字符串指针需要加& return 0; }
🔍2.1.2 C语言解决方案
按行获取字符串:char *fgets(char *str, int n, FILE *stream);
str
是一个指向字符数组的指针,用于存储读取的字符。n
是要读取的最大字符数(包括终止符\0
),即字符数组的大小。stream
是文件流指针,指定从哪个文件流中读取字符,通常可以是stdin
(标准输入)、stdout
(标准输出)等。- 注意str会包含换行符,需要删去换行符: str[strcspn(buffer, "\n")] = '\0';
const int MaxSize=100; char buffer[MaxSize]; fgets(buffer, sizeof(buffer), stdin);//按行获取字符串 buffer[strcspn(buffer, "\n")] = '\0';//不能是'\n'
程序示例:
#include <stdio.h> #include <string.h> int main() { const int maxSize = 100; char buffer[maxSize]; printf("Enter a line of text:\n"); fgets(buffer, sizeof(buffer), stdin);//按行获取字符串 buffer[strcspn(buffer,"\n")]='\0';//不能是'\n' printf("You entered: %s", buffer); return 0; }
🌐2.2 获取字符串长度
最好使用
int slen=s.length();
在使用slen.直接使用s.length()造成的问题会很麻烦,
#include <iostream> #include <string> using namespace std; int main(){ string s; getline(cin,s);//hello cout<<s.length()<<endl;//5 //而使用s1.length报错 return 0; }
🌐2.3 字符串和字符数组的结束标志
字符串结束标志是'\0',若字符数组是以字符串形式输入,则结束标志也是'\0'
注意:
- '\0'是结束标志,而不是"\0"
- '\n'是换行符而不是"\n"
🕵️♀️3. C/C++的结构体注意点
在C语言,结构体声明和C++不同,见😎3.2 KiKi设计类继承
解决办法:C++中设计结构体不要用typedef
/*C语言*/ typedef struct Shape{ int x,y; }Shape; //后续定义才能为 Shape shape; struct Shape{ int x,y; }; //后续定义为 struct Shape shape; /*C++*/ typedef struct Shape{ int x,y; }Shape; //这样做导致声明了 Shape为全局变量,可能导致后续Shape类型出现问题 //,所以在C++尽量不要使用typedef //上述内容等价于 struct Shape { int x, y; }; typedef struct Shape Shape; struct Shape{ int x,y; }; //后续定义为 struct Shape shape; 或者 Shape shape;
🕵️♀️4. 继承注意点
🌐4.1 构造函数
派生类的构造函数,需要保证调用基类的构造【默认调用基类无参构造,如果基类创新提供了新的有参构造,则派生类的构造易出错】,见😎3.3 牛牛的书
解决办法:最好每次提供新的构造函数时都再提供一个无参的默认构造函数。
🔍4.1.1 构造函数的形参
构造函数的参数最好不要和class 的数据同名,否则需要加上this,不然出错!
#include <iostream> using namespace std; class Base { private: int x; int y; public: //构造函数 Base(int x, int y) { this->x = x;//x=x is error this->y = y;//y=y is error } Base(){} int getX() { return x; } int getY() { return y; } }; int main() { int x, y; cin >> x; cin >> y; Base base(x,y); cout<<base.getX()<<" "<<base.getY()<<endl; return 0; }
🔍4.1.2 构造函数的继承
派生类的构造函数调用前需要调用基类的构造函数,并且派生类新增数据需要加this,否则出错。
#include <iostream> using namespace std; class Base { private: int x; int y; public: //构造函数 Base(int x, int y) { this->x = x; this->y = y; } Base(){} int getX() { return x; } int getY() { return y; } }; class Sub : public Base { private: int z; public: //构造函数 Sub(int a, int b, int c) :Base(a, b) {//继承基类的构造 this->z=z;//必须加this,虽然基类没有z成员 } Sub():Base(){} int getZ() { return z; } int calculate() { return Base::getX()*Base::getY()*this->z;//调用基类数据成员需要加域 Base:: } }; int main() { int x, y, z; cin >> x; cin >> y; cin >> z; Sub sub(x, y, z); cout << sub.calculate() << endl; return 0; }
🌐4.2 纯虚函数
纯虚函数:
纯虚函数本身在基类中没有具体的实现,而是在派生类中被强制要求实现。
纯虚函数的声明和定义的一般形式如下:
class AbstractBase { public: virtual void A() const = 0; // 纯虚函数声明,不是xx(){} const=0; virtual ~AbstractBase() {} // 虚析构函数 };
注意:
- 后续派生类实现必须是
class AbstractBase { public: virtual void A() const = 0; // 纯虚函数声明,不是xx(){} const=0; virtual ~AbstractBase() {} // 虚析构函数 }; class B{ public: virtual void A() const{//virtual可以省略,const不能省略 ... } ... }
🕵️♀️5. 限制输出注意点
C++使用cout<<进行输出。
添加头文件#include + #include
注意
- 输出%,则printf("%%");
setprecision、fixed
会影响接下来的所有浮点数的输出,直到下个setprecision、fixed
出现为止。setprecision(2)表示精确2位,如 11.235 则输出 11 3.14 输出 3.1
要求精确到小数点后n位,使用cout<
/*限定输出格式*/ #include <iostream> #include <iomanip> using namespace std; int main() { double a = 11.2345; cout << setprecision(2) << a << endl; // 精确输出2个,这里输出11 cout << fixed<<setprecision(2) << a << endl; // 保留2位小数,输出11.23 cout << setw(8) << a << endl; // 控制输出宽度为8,右对齐(默认) cout << right << setw(8) << a << endl; // 控制输出宽度为8,右对齐 cout << left << setw(8) << a << endl; // 控制输出宽度为8,左对齐 } /*输出 11 11.23 11.23 11.23 11.23 */
🕵️♀️6. new/delete注意点
注意:使用new之后求数组大小
int maxSize; cin>>maxSize; int *a=new int[maxSize]; //求动态数组大小 int n=sizeof(a)/sizeof(a[0]);//error! n===0 sizeof(a)===8 int b[5]; int n=sizeof(b)/sizeof(b[0]);//ok
new分配的大小恒等于8
#include <iostream> using namespace std; //Array类 class Array{ private: int n; int *array; public: Array(int *a){ n=sizeof(a)/sizeof(a[0]); cout<<"n="<<n<<endl; array=new int[n]; for(int i=0;i<n;i++){ array[i]=a[i]; } } Array(){} ~Array(){ delete [] array; } }; int main(){ int maxSize; cin>>maxSize; int *a=new int[maxSize]; for(int i=0;i<maxSize;i++){ cin>>a[i]; } int n=sizeof(a)/sizeof(a[0]); cout<<"n="<<n<<endl; Array array(a); return 0; }
🕵️♀️7. 数组注意点
🌐7.1 数组输入
下面的示例,两种输入都正确。
#include <iostream> using namespace std; int main(){ int n; cin>>n; int *a=new int[n]; for(int i=0;i<n;i++){ cin>>a[i]; } for(int i=0;i<n;i++){ cout<<a[i]<<" "; } delete [] a; cout<<endl; }
🌐7.2 数组初始化
详见下面的示例
#include <iostream> using namespace std; //输出数组 void Disp(int *a,int n){ for(int i=0;i<n;i++){ cout<<a[i]<<" "; } cout<<endl; } int main(){ int a[10]={1,0,2,3,6,5,4,7,8,9}; int n=sizeof(a)/sizeof(a[0]); Disp(a,n); a={0,1,2,3,4,5,6,7,8,9};//报错,只能在声明+定义时这样初始化 Disp(a,n); return 0; }
🕵️♀️8. STL
🌐8.1 vector
vector的输入需要注意:详见2.3【C++】STL的基本用法
🕵️♀️9. 函数传参注意点
🌐9.1 参数
关于
void sort(vector &v); //main()传递参数直接 sort(v);
void sort(LNode **L); //main()传递参数直接 sort(&L);