一、隐式类型转换:
1、转换的类型:
隐式类型转换:意义相似的类型(如:int与double可以,string和vector不行)
显式的强制类型转换:int与int*
自定义类型:单参数构造函数支持隐式类型转换。
#include<iostream>
using namespace std;
class A
{
public:
A(int a)
:_a(a)
{
cout << "A(int a)" << endl;
}
A(const A& aa)
:_a(aa._a)
{
cout << "A(const A& aa)" << endl;
}
//禁止隐式类型转换
// explicit A(int a)
// :_a(a)
// {
// cout << "A(int a)" << endl;
// }
private:
int _a;
};
int main()
{
A aa1(1);
A aa2 = 2;//隐式类型转换(整形转换为自定义类型)
//2构造了一个A的临时对象,临时对象再拷贝构造aa2-->优化用2直接构造
int i = 10;
double d = i;
const A& aa3 = 2;//隐式类型转换会产生临时变量,临时变量具有常性
return 0;
}
volatile修饰的变量,每次都要去内存取:
int main()
{
// volatile 修饰的变量,每次都要去内存取,否则经过编译器优化后去寄存器取
volatile const int n = 10;
// 转换有安全隐患的
int* p = (int*)&n;
(*p)++;
cout << n << endl;
cout << *p << endl;
cout << p << endl;//虚拟地址
return 0;
}
2、C++强制类型转换:
标准C++为了加强类型转换的可视性,引入了四种命名的强制类型转换操作符:static_cast、reinterpret_cast、const_cast、dynamic_cast。
①static_cast:用于非多态类型的转换(静态转换),但它不能用于两个不相关的类型进行转换。
②reinterpret_cast:用于将一种类型转换为另一种不同的类型(为操作数的位模式提供较低层次的重新解释)。
③const_cast:删除变量的const属性,方便赋值。
int main()
{
// 相关类型/相近类型
double d = 12.34;
int a = static_cast<int>(d);
cout << a << endl;
// 不相关类型
int* p1 = &a;
int address = reinterpret_cast<int>(p1);
// 去掉const属性
volatile const int n = 10;
int* p2 = const_cast<int*>(&n);
return 0;
}
④dynamic_cast:用于将一个父类对象的指针/引用转换为子类对象的指针或引用(动态转换)
向上转型:子类对象指针/引用->父类指针/引用(不需要转换,赋值兼容规则)
向下转型:父类对象指针/引用->子类指针/引用(用dynamic_cast转型是安全的)
注意:
1. dynamic_cast只能用于父类含有虚函数的类
2. dynamic_cast会先检查是否能转换成功,能成功则转换,不能则返回0
class A
{
public:
virtual void f() {}
int _x = 0;
};
class B : public A
{
public:
int _y = 0;
};
void fun(A* pa)
{
// pa是指向子类对象B的,转换可以成功,正常返回地址
// pa是指向父类对象A的,转换失败,返回空指针
B* pb = dynamic_cast<B*>(pa);
if (pb)
{
cout << "转换成功" << endl;
pb->_x++;
pb->_y++;
}
else
{
cout << "转换失败" << endl;
}
}
int main()
{
A aa;
fun(&aa);
B bb;
fun(&bb);
return 0;
}
二、static成员
//实验
#include<iostream>
using namespace std;
int _scount = 0;
class A
{
public:
A() { ++_scount; }
A(const A& t) { ++_scount; }
~A() { --_scount; }
private:
};
A aa0;
A Func(A aa1)
{
cout << __LINE__ << ":" << _scount << endl;//打印 21:4
return aa1;
}
int main()
{
cout << __LINE__ << ":" << _scount << endl;//打印 29:1
A aa1;
static A aa2;
Func(aa1);
cout << __LINE__ << ":" << _scount << endl;//打印 33:3
return 0;
}
· 成员变量属于每个类对象,存储在对象里。
静态成员变量,属于类,属于类的每个对象共享,存储在静态区。需要在全局位置,类外面定 义。(突破一次私有)
· 静态成员,没有this指针(不能访问非静态成员),只要突破/指定类域和访问限定符/友元,就 可以访问。
· 静态成员函数和静态成员变量配套出现。
· 静态成员变量不能给缺省值(因为他没有初始化列表)(缺省值是给初始化列表的)。
· 静态成员在类里面声明,类外面定义,且不受访问限定符的限制。
· 静态不可以调用非静态(非静态的成员函数调用需要this指针,而静态没有),非静态可以调用 静态
#include<iostream>
using namespace std;
class A
{
public:
A() { ++_scount; }
A(const A& t) { ++_scount; }
~A() { --_scount; }
void Func1()
{
// 非静态能否调用静态:可以
GetACount();
}
void Func2()
{
++_a1;
}
// 没有this指针,指定类域和访问限定符就可以访问
static int GetACount()
{
// 静态能否调用非静态:不可以。非静态的成员函数调用需要this指针,而静态的成员函数没有this指针
// Func2();
return _scount;
}
private:
// 成员变量 -- 属于每个一个类对象,存储对象里面
int _a1 = 1;
int _a2 = 2;
//public:
// 静态成员变量 -- 属于类,属于类的每个对象共享,存储在静态区
static int _scount;
};
// 全局位置,类外面定义
int A::_scount = 0;
A aa0;
void Func()
{
static A aa2;
cout << __LINE__ << ":" << aa2.GetACount() << endl;// 3
// 全局变量的劣势:任何地方都可以随意改变
//_scount++;
}
int main()
{
cout <<__LINE__<<":"<< A::GetACount() << endl; // 1
A aa1;
Func(); // 3
return 0;
}
//设计一个类,在类外面只能在栈和堆上创建对象
#include<iostream>
using namespace std;
class A
{
public:
static A GetStackObj()
{
A aa;
return aa;
}
static A* GetHeapObj()
{
return new A;
}
private:
A()
{}
private:
int _a1 = 1;
int _a2 = 2;
};
int main()
{
//static A aa1; // 静态区
//A aa2; // 栈
//A* ptr = new A; // 堆
A::GetStackObj();
A::GetHeapObj();
return 0;
}
三、匿名对象
· 有名对象--生命周期在当前函数局部域。
匿名对象--生命周期在当前行,即用即销毁。
· 匿名对象具有常性(和临时对象一样)。
引用需加const,Const引用延长匿名对象的生命周期,生命周期在当前函数局部域。
#include<iostream>
using namespace std;
class A
{
public:
A(int a = 0)
:_a(a)
{
cout << "A(int a)" << endl;
}
~A()
{
cout << "~A()" << endl;
}
private:
int _a;
};
class Solution {
public:
int Sum_Solution(int n) {
cout << "Sum_Solution" << endl;
//...
return n;
}
};
void push_back(const string& s)
{
cout << "push_back:" << s << endl;
}
int main()
{
A aa(1); // 有名对象 -- 生命周期在当前函数局部域
A(2); // 匿名对象 -- 生命周期在当前行
Solution sl;
sl.Sum_Solution(10);
//Solution s1();//不能这么定义,因为无法区分是对象还是函数名
Solution().Sum_Solution(20);
//不能这样调用,因为匿名对象不包含this指针(只能调没有this指针的静态成员函数)
//A& ra = A(1); // 匿名对象具有常性
const A& ra = A(1); // const引用延长匿名对象的生命周期,生命周期在当前函数局部域
//string str("11111");
//push_back(str);
//push_back(string("222222"));
push_back("222222");//匿名对象的应用
return 0;
}