1.指针和引用
1.1定义与特点
指针本身命名变量,有地址,可变,可以为空值;
引用是变量的别名,必须初始化,从一而终不可变,不存在指向空值的引用。
1.2用途
指针:用于动态内存分配、数组操作及函数参数传递;
引用:用于函数参数传递、操作符重载及创建别名。
2.数据类型
2.1整型
short:至少16位;
int:至少与short一样长;
long:至少32位&&至少与int一样长;
long long:至少64位&&至少与long一样长
2.2无符号类型
不存储负数值的类型,增大变量能够存储的最大值。
注:int一般被设置为自然长度,选择类型时一般选用int类型。
3.关键字
3.1const
const的语义为只读。修饰的值不能改变,必须在定义时就给它赋予初值。
3.1.1常量指针
常量的指针,是底层const,即指针指向的是一个只读的对象。const在*左边,靠近数据类型。
示例:
int a = 10;
int b = 20;
const int * pa = &a; //int const * pa = &b;
pa = &b; //pa的值可变
cout<<*pa<<endl; //20
3.1.2指针常量
指针类型的常量,是顶层const,指针常量只能在定义时初始化,之后不能改变。const在*右边,靠近变量名。
int a = 10;
int * const pa = &a;
*pa = 20; //pa指向的对象值可变
cout<<*pa<<endl; //20
3.1.3修饰引用
表示引用的值是常量,不能通过引用修改。
3.2static
static用于控制变量和函数的生命周期、作用域及访问权限。
3.2.1修饰变量
静态变量在程序的整个生命周期存在,不会因为离开作用域而被销毁,但修饰的局部变量还是只能在声明它的函数内可见。默认初始化为0(基本数据类型)。
如果修饰的是类的成员变量,所有类的对象共享同一个静态成员变量,且必须在类外部定义,以分配内存。
3.2.2修饰函数
一般修饰类的成员函数,静态成员函数可以通过类名调用而不需要创建对象,不能直接访问非静态成员变量或非静态成员函数。
class Example{
static int val;
public:
static void anotherStaticMethod(){
cout<<"I am another static method!"<<endl;
}
static void staticMethod(){
cout<<val<<endl;
anotherStaticMethod();
}
};
int Example::val = 10;
int main(){
Example::staticMethod();
//10
//I am another static method!
return 0;
}
3.4. define、typedef、inline
define:定义预编译时处理的宏,字符串替换,无类型检查,不安全。用来防止头文件重复引用。
typedef:有对应的数据类型,有类型安全检查,在编译运行时起作用。
inline:对编译器的一种要求(编译器可以拒绝),inline会将其修饰的函数编译生成的函数体直接插入到被调用的地方,没有普通函数的压栈,跳转和返回开销。内联函数是一种特殊的函数,会进行类型检查。
注:内联函数中不能有循环语句,过多的条件判断,函数体要小,且必须声明在调用语句之前。
3.5.new/delete和malloc/free
new/delete:C++的运算符,自动计算要分配的内存大小,除了分配和释放内存还会调用构造和析构函数,返回定义时具体类型的指针,失败抛出bad_alloc异常,是类型安全的;
malloc/free:C++/C语言的标准库函数,要手动计算内存大小,只分配和释放内存,返回的是void*类型的指针,需要进行类型转换,不是类型安全的;
3.6.constexpr
表示 ”常量“ 的语义,且只能定义编译期常量,一个constexpr标记的变量或函数是const的,反之则不是。
constexpr修饰的指针是常量。修饰的函数的返回类型和所有形参类型都是字面值类型,函数有且只有一条return语句。
3.7volatile
是类型修饰符,影响编译器的结果,修饰的变量有关的操作,不会编译优化,也就是变量的值每次都只会去内存中取,而不会去寄存器中取。
3.8struct 和class
通常struct用于一组相关的数据(也可以有函数),成员默认public,继承默认public;
class包括数据和操作,成员默认private,继承默认private;
3.9前置++与后置++
class Example{
public:
int val;
//前置++
Example &operator++(){
val += 1;
return *this;
}
//后置++
const Example operator++(int){ //形参只是为了作区分//不能返回引用
const Example tmp = *this; //const是为了防止++++出错的情况
val += 1;
return tmp;
}
};
int main(){
Example t;
t.val = 0;
cout<<t.val<<endl; //0
++t;
cout<<t.val<<endl; //1
t++;
cout<<t.val<<endl; //2
return 0;
}
注:推荐使用前置++,不会创建临时对象,也就不会有构造和析构造成的额外开销。
4.函数指针
指向函数指针变量,用于存储函数地址,允许运行时动态选择要调用的函数。
int add(int a, int b){
return a+b;
}
int main(){
int (*pExample)(int, int);
pExample = &add;
cout<<add(1, 2)<<endl; //3
return 0;
}
使用场景:
- 回调函数:向一个函数传递函数指针,以在合适的时候调用及可插拔的特性;
- 函数指针数组:根据不同的状态调用不同的函数;
- 动态加载库:实现动态链接库的调用;
- 多态实现:虚函数和函数指针结合使用,实现动态多态;
注:指针函数,返回指针类型的函数,尽量不要这么做。
int * getPtr(){
int x = 10;
return &x;
}
5.变量使用场景
(从作用域,生命周期,关键字,初始化等方面考量)
静态局部变量:定义的函数内,static修饰,第一次调用时初始化,与程序的生命周期相同。
全局变量:定义在函数和类外,作用域和生命周期都在程序,通常用于共享数据。
6.强制类型转换
static_cast:用于基本类型之间的转换,及将任何类型的表达式转换成void类型。上行转换安全,下行转换不安全。
class Base {
public:
virtual void print() {
cout << "Base class" << endl;
}
};
class Derived : public Base {
public:
void print() override {
cout << "Derived class" << endl;
}
};
int main(){
Base* basePtr = new Derived();
basePtr->print(); //Derived class
// 使用 static_cast 将基类指针转换为派生类指针
Derived* derivedPtr = static_cast<Derived*>(basePtr); //下行是不安全的
// 调用派生类的方法
derivedPtr->print(); //Derived class
char c = 'a';
int i = static_cast<int>(c); //97
cout<<i<<endl;
c = static_cast<char>(i); //a
cout<<c<<endl;
return 0;
}
dynamic_cast:只用于存在虚函数的父子关系的强制类型转换。转换后必须是类的指针、引用或void*。对于指针/引用,转换失败返回nullptr/抛出异常。下行转换有类型检查,比static_cast更安全。
class Base {
public:
virtual void print() { cout << "Base class" << endl; }
};
class Derived : public Base {
public:
void print() override { cout << "Derived class" << endl; }
};
int main() {
Base* basePtr = new Derived();
// 使用 dynamic_cast 将基类指针转换为派生类指针
Derived* derivedPtr = dynamic_cast<Derived*>(basePtr);
if (derivedPtr) {
// 如果转换成功,调用派生类的方法
derivedPtr->print();
} else {
// 如果转换失败,则 basePtr 不是派生类的指针
cout << "Cannot convert to Derived class" << endl;
}
return 0;
}
reinterpret_cast:将整型转换为指针,指针转换为数组以及指针和引用的转换。
const_cast:常量指针/引用转换为非常量指针/引用,指向的对象相同。去掉类型的const或volatile属性。
class MyClass {
public:
int value;
MyClass(int value) : value(value) {}
int getValue() const { return value; }
};
int main() {
const MyClass obj(10);
// 使用 const_cast 将 const 对象转换为非 const 对象
MyClass& nonConstObj = const_cast<MyClass&>(obj);
// 修改非 const 对象的值
nonConstObj.value = 20;
// 打印修改后的值
cout << obj.getValue() << endl; // 输出:20
return 0;
}