加在类构造函数前表明该构造函数是显式的,并非隐式的,不能进行隐式类型转换!
类构造函数默认情况下声明为隐式。
给构造函数加上关键字explicit使得该类创建对象必须显式调用构造。
student xiaohua(18);//显式构造
student xiaoming = 18;//隐式构造
student xiaoli("小李",18);//显式构造
student xiaomei = ("小美",18);//隐式构造-C++11之前编译不能过
//初始化参数列表C++11新增
看到=要想是赋值呢,还是隐式构造呢。
按字面意思,通俗的说,以赋值运算符=为界,左边的就是左值,右边的就是右值。
左值(lvalue)——代表一个在内存中占有确定位置的对象(就是有一个地址)。
右值(rvalue)——通过排他性来定义,每个表达式不是左值就是右值,rvalue是不在内存中占有确定位置的表达式,而是在存在寄存器中。
所有的左值(无论是数组,函数或不完全类型)都可以转化成右值。
C++使用引用时的难点
详见-C++SLT容器中。
(取容器中元素的地址貌似是没有意义的,除非他里面的内容不在改变,因为有的容器中元素发生变化后,里面的容器元素是会发生移动的。)
其中,有意思的是empty()接口永远false,因为在构造的时候要指定数量。
C语言风格
double PI = 3.1415926;
int i = PI;//隐式类型转换
int i1 = (int)PI;//显式类型转换
int* addr = (int*)0x888888;//强制类型转换,整数直接指针
C++类型转换操作符
静态类型转换,同时做检查给予提示。
int i = static_cast<int>(PI);
//父子类之间的类型转换
Dog* dog = new Dog;
//子类指针转型到父类指针
Animal* animal = static_cast<Animal*>(dog);
//父类指针转型到子类指针
Dog* dog2 = static_cast<Dog*>(animal);
Dog dog2;
//子类引用转型到父类引用
Animal& animal2 = static_cast<Animal&>(dog2);
//基本类型转换
int kk = 234;
char cc = static_cast<char>(kk);//都是模板
//把空指针转换成目标类型的空指针
int* p = static_cast<int*>(NULL);
Dog* dp = static_cast<Dog*>(NULL);
//把任何类型的表达式转化成void类型
int* p = new int[10];
void* vp = static_cast<void*>(p);
vp = p;//效果相同
主要用法:
(写了会提醒编译器检查,提醒其他程序员要注意。)
(没事别转。)
(可以用于强制类型转换)
重新解释类型不同类型间的互转,数值与指针间的互转。
用法: TYPE b = reinterpret_cast < TYPE> (a)
TYPE必须是一个指针、引用、算术类型、函数指针.
int* p = reinterpret_cast<int*>(0x999999);//整型转指针
int* val = reinterpret_cast<int>(p);//指针转整型
Dog dog1;
Animal* a1 = &dog1;
Animal& a2 = dog1;
Dog& dog3 = reinterpret_cast<Dog&>(a2);//引用强转用法
注意:滥用 reinterpret_cast 运算符可能很容易带来风险。 除非所需转换本身是低级别的,否则应使用其他强制转换运算符之一。(低级别:在内存没啥差别)
与static_cast相加可替换掉C风格的类型转换。
动态类型转换
将一个基类对象指针cast到继承类指针,dynamic_cast 会根据基类指针是否真正指向继承类指针来做相应处理。失败返回null,成功返回正常cast后的对象指针。
( 看该父类是否真正指向该子类(因为有多个子类。))
(子类* xx = dynamic_cast<子类*>(父类xx);
将一个基类对象引用cast 继承类对象,dynamic_cast 会根据基类对象是否真正属于继承类来做相应处理。失败抛出异常bad_cast。
void animalPlay(Animal* animal) {
animal->cry();
Dog* pDog = dynamic_cast<Dog*>(animal);
if (pDog) {
pDog->play();
}
else {//pDog == NULL
cout << "不是狗,别骗我!" << endl;
}
Cat* pCat = dynamic_cast<Cat*>(animal);
if (pCat) {
pCat->play();
}
else {//pDog == NULL
cout << "不是猫,别骗我!" << endl;
}
}
void animalPlay(Animal& animal) {
animal.cry();
try {
Dog& pDog = dynamic_cast<Dog&>(animal);
pDog.play();
}
catch (std::bad_cast bc) {
cout << "不是狗,那应该是猫" << endl;
}
try {
Cat& pCat = dynamic_cast<Cat&>(animal);
pCat.play();
}
catch (std::bad_cast bc) {
cout << "不是猫,那应该是上面的狗" << endl;
}
注意: dynamic_cast在将父类cast到子类时,父类必须要有虚函数一起玩。
去掉const属性,仅针对于指针和引用。
void demo(const char p)
{
//对指针去掉const 重新赋值
char* p1 = const_cast<char*>(p);
//直接去掉const修改
const_cast<char*>(P)[0] = 'a';
}
常量字符串不行,考虑内存范围。
在去掉常量限定符之前,保证指针所指向的内存可被修改,不能修改则会引起异常。
C语言中 能隐式类型转换的,在c++中可用 static_cast<>()进行类型转换。因C++编译器在编译检查一般都能通过;C语言中不能隐式类型转换的,在c++中可以用 reinterpret_cast<>() 进行强制类型解释**。
总结:static_cast<>()和reinterpret_cast<>() 基本上把C语言中的 强制类型转换给覆盖,注意reinterpret_cast<>()很难保证移植性。
3.dynamic_cast<>(),动态类型转换,安全的虚基类和子类之间转换;运行时类型检查
4.const_cast<>(),去除变量的只读属性
程序员必须清楚的知道: 要转的变量,类型转换前是什么类型,类型转换后是什么类型,转换后有什么后果。
一般情况下,不建议进行类型转换;避免进行类型转换。