第六课 类型转换
一、static_casr(expr)
1、作用:相关数据类型之间的转换。
(1)类似于C语言的强制转化,保证代码的安全性和正确性。
(2)可用于①相关类型转换;例如整型、实型;②子类转父类;
③ void
*指针与其他类型指针之间的类型转换。
(3)不允许指针之间类型的转换(特例:仅允许void*与其他指针之间的类型转换)。
如:char ch = ‘a’;
char
*pc = &ch;
int
*pt = static_cast<int *>(pc); //指针类char
*->int *
//上方代码是该类错误示例
注:①指针之间的赋值规则:必须是相同指针类型之间赋值(相同步长)。
② void*是万能指针,可以接受任何指针的类型。
2、使用示例:
(1)非指针类型间转换
double b =1.234;
int a = static_cast(b); //double->int ;
char ch = static_cast(a); // int->char;
(2)void *指针与其他类型指针之间的转换
int *pa = &a;
void *p = pa;
int *pa 2= static_cast<int
*>§ ; //指针类void *->int *
二、const_ casr(expr)
1、作用:只能用于去除指针和引用的const属性。
注:使用该运算符转换意味着代码设计上存在缺陷。
2、使用示例:
(1)
去除指针
int a = 1;
const int *pa4 = &a; //pa4指针
int *pa5 = const_cast<int *>(pa4);
//去除const
int *pa4的const属性成为int
*pa4赋左
(2)
去除引用
int a = 1;
const int &la = a; //la引用
int &la2 = const_cast<int &>(la);
//去除const
int &la的const属性成为int
&la赋左
三、dynamic_cast(expr)
1、作用:运行时类型识别和检查,用于父类子类之间的转换。
四、reinterpret_ casr(expr)
1、作用:任意无关类型之间的转换。
注:①与static_cast区别在于类型之间有无相关性(指针类-步长是否相等)。
②其他类型是允许const赋值给非const类型的。
2、特点:不安全,既不在编译器期也不在运行期进行检查,安全性完全由程序员决定。
3、使用示例:
char *pc = &ch;
int *pa3 = reinterpret_ casr<int
*>(pc); //指针类char *->int *
4、错误示例:
int a = 1;
float c = reinterpret_cast(a);
//int->float
错误原因:int、float为相关的数据类型。
第七课 C++的封装
一、封装
1、封装作用:对外提供接口,屏蔽数据,对内开放数据。
2、C语言的封装:当单一变量无法完成描述需求的时候,封装成函数或结构体类型解决。
问题:即知其接口,又可以直接访问其内部数据。
注:C语言中的封装内容不能是函数(C++中的class可实现),结果可以是函数。
3、C++的封装:class 封装的本质,在于将数据和行为绑定在一起,再通过对象来完成操作。
二、类与对象
1、类的声明:
class
类名称
{
public:
公有成员(外部接口)
private:
私有成员
protected:
保护成员
};
2、权限修饰符:public、private(set/get)、protected
①public后面声明,它们是类与外部的接口,任何外部函数都可以访问公有类型数据和函数。
②private后面声明,只允许本类中的函数访问,而类外部的任何函数都不能访问。
③protected后面声明,与private类似,其差别表现在继承与派生时对派生类的影响不同。
3、class的get/set(在公有中获取私有变量)方法:提供相对安全方式访问成员变量。
4、面向对象编程实例:栈的实现。
5、面向对象的代码结构:使用.h定义类,使用.cpp实现类里的方法,主函数main.cpp。
5、C++栈的实现示例:
Stack.h文件 Stack.cpp文件(1)
Stack.cpp文件(2) main.cpp文件
三、class的构造函数
1、作用:初始化对象的属性。
2、特点:①没有函数返回值;②函数名与类型相同;
③可以重载;④实例(定义)一个对象会自动调用构造函数。
3、种类:
①默认的无参构造函数;②无参构造函数;③类型转换构造函数;
④默认拷贝构造函数;⑤移动拷贝构造函数(、⑥初始化列表)。
4、使用示例:
(1)
默认的无参构造函数:类里没有任何自定义的构造函数时,会默认生成Test()。
class Test
{
public:
…….
//此处无特意自定义的无参构造函数
//则默认生成一个Test()
private:
int m_num;
int m_age;
string m_name;
char *m_addr;
};
Int main()
{
Test t;
//会调用默认生成的无参构造函数
………
return 0;
}
(2)
自定义的无参构造函数
class Test
{
public:
Test() //无参的构造函数
{
m_num = 0;
m_age = 0;
m_name = “jsetc”;
m_addr = new char[20];
cout << “Test” <<
endl;
}
Test(int num,int age,string
name,const char *addr) //重载的构造函数
{
m_num = num;
m_age = age;
m_name = name;
m_addr = new char[20];
strcpy(m_addr,addr);
cout << “Test(int num,int
age, string name,char *addr)” << endl;
}
…….
private:
…….
};
int main()
{
Test
t(1,23,“zhangsan”,“nanjing”);
//以上方重载的函数为例,会自动调用构造函数
cout <<
t.getName() << endl; // getName()在public:中
return 0;
}
(3)
类型转换构造函数:一个参数的构造函数;
注:存在风险–将其他类型默认转换为类类型;通过explicit修饰构造函数,防止发生默认转换。
class Test
{
public:
………
explicit Test (int num)
//类型转换构造函数:explicit防止发生隐式类型转换
{
cout << " Test int" <<
endl;
m_num = num;
}
…….
private:
…….
};
int main()
{
Test a1{1}; //std::initializer_list
//类中自动生成 Test (std::initializer_list l)
//但当类中有系统自己定义的构造函数时,系统不会默认生成
Test
a2 = {2};
// Test a3 = 3; //错误:将一个整型常量赋值给一个Test类型的对象
//发生了隐式类型转换(存在风险)解决方法:加explicit
……
return 0;
}
(补充): 使用static_cast转换类型,需在public中添加operator。
class Test
{
public:
…….
operator int()
//类类型转换运算符重载:支持static_cast()
{
return m_num;
}
operator string() //支持static_cast()
{
return m_name;
}
…….
};
int main()
{
Test a4;
int num = static_cast(a4);
cout << num << endl;
string name = static_cast(a4);
………
return 0;
}
(4) 默认的拷贝构造函数:当类中无拷贝构造函数时,系统会默认生成一个拷贝构造函数: Test (const Test &a);
(5) 自定义拷贝构造函数(拷贝!= 赋值)
class Test
{
public:
…….
A(const A &other) //自定义的拷贝函数
{
m_num = other.m_num;
cout << “A cope A”
<< endl;
}
private:
…….
};
int main()
{
A
a1(a);//调用拷贝构造函数A(const A &other)
A
a3 = a;//调用拷贝构造函数A(const A &other)
//A
a2; a2 = a;//赋值运算符
!= 拷贝
return 0;
}
(补充):赋值运算符重载(即上方的A a2; a2 = a;)
A& operator =(const A &other) //添加在类中验证赋值运算符 != 拷贝
{
cout << “A operator A” << endl;
m_num = other.m_num;
}
四、class的析构函数
1、作用:释放对象给属性分配的空间。
2、特点:①没有返回值;②不能重载;
③函数名:~类名;④当实例的对象释放空间时被调用。
3、使用示例:
class Test
{
public:
………
~Test() //析构函数,main中使用Test+变量名 会自动调用
{
cout << “~Test” << endl;
delete m_addr; //若无此语句,m_addr所占资源将无法释放
//可释放构造函数中的变量char
m_addr[20]的空间
}
………
private:
………
};