C++基础(三)
类型转换与C++的类(部分)
一、C++中的类型转换 在C++中,某些类型之间有关联,因此他们之间可以进行数据转换,对于算术运算,比如一个整型与一个浮点型相加,C++会就根据类型规则设法将运算对象的类型统一,这种操作称为隐式转换。 1、显式转换 有时我们希望将对象强制转换为另外一种类型,这种方法称为强制类型转换。 命名的强制类型转换。
cast_name<type> (expression)
type就是我们希望的类型,expression是目标值,cast_name是static_cast, dynamic_cast, const_cast和reinterpret_cast中的一种。 (1) static_cast 任何具有明确定义的类型转换,只要不包含底层const,都可以使用该方法。 (2)const_cast const_cast只能改变对象的底层const,该方法的作用是去掉对象的const属性,以此来获取常量对象的写权限。 (3) reinterpret_cast 该方法通常为运算对象的位模式提供较低层次上的重新解释(不常用且操作危险)。 二、try语句块和异常处理 异常是指存在于运行中的反常行为,这些行为超出了函数正常功能的范围。当程序的某部分检测到一个他无法处理的问题时,需要用到异常处理。 在C++中,异常处理包括: 1、throw表达式,异常检测部分使用了throw表达式表示他遇到了无法处理的问题。 2、try语句块,异常处理部分使用try语句块处理异常。try语句块以try开头,并以一个或者多个catch子句结束。此部分也叫做异常处理代码。 3、一套异常类,用于在throw表达式和相关的catch子句之间传递异常的具体信息。 书上的代码,自己敲了下好像并没有抛出异常,可能方法不对。
while (cin >> a >> b)
{
try
{
}catch (runtime_error err)
{
cout << err.what() << "\nTry Again? Enter y oy n" << endl;
char c;
cin >> c;
if (!cin || c == 'n')
{
break;
}
}
}
三、C++中的类(函数章节跳过) 类的基本思想是数据抽象和封装。数据抽象是一种依赖于接口和实现分离的编程技术。类的接口包括用户所能执行的操作:类的实现规则包括类的数据成员、负责接口实现的函数体以及定义类所需的各种私有函数。 1、类作用域与成员函数 类本身是一个作用域,类的成员函数的定义嵌套在类的作用域之内。编译器在处理类的时候分为两步:首先编译成员的声明,然后编译成员函数体,因此函数定义在变量之前并引用变量,也不会引起错误。因此,成员函数体可以随意使用类中的其他成员而无需在意这些成员出现的次序。 在类的外部定义成员函数也是允许的,但是其返回类型、参数列表、和函数名都要与类内部的声明保持一致。 注意:成员函数的定义需要与声明相匹配。例如在类Data_class外创建一个函数fun1:
Data_class::fun1(param){;}
2、定义类相关的非成员函数 定义非成员函数的方式与定义其他函数一样,通常把函数的声明和定义分离开来;如果函数在概念上属于类但是不定义在类里面,则它一般应该与类声明在同一头文件内。 3、构造函数 每个类都分别定义了它的对象被初始化的方式,类通过一个或者几个特殊的成员函数来控制其对象的初始化过程,这些函数叫做构造函数。构造函数的作用是初始化类对象的数据成员,无论何时只要类被创建,就会执行构造函数。 默认构造函数: 如果我们的类没有显式的定义构造函数,那么编译器就会为我们隐式的创建一个默认构造函数来初始化成员。 4、访问控制与封装 在C++语言中,使用访问说明符加强类的封装性。 ---->>>定义在public说明符之后的成员在整个程序内可以被访问,public定义了类的接口 ---->>>定义在private说明符之后的成员可以被类的成员函数访问,但是不能被使用该类的代码访问,其实就是保留了一部分访问权限。 重要:使用struct和class都可以定义一个类,但是两种定义方式的区别在于其默认的访问权限。 struct:在第一个访问说明符之前默认成员都是public的 class:在第一个访问说明符之前默认成员都是private的 简单的例子
class Sales_data
{
void fn1()
{
cout << name << endl;
}
void fn2()
{
}
void fn3()
{
;
}
std::string name;
};
这样定义一个类,不能访问其中的任何成员。
友元(friend):为了能够让其他非类函数读取类的private类型的成员,可以令其他类或者函数成为它的友元(friend),使用以friend关键字开头的函数声明即可:
friend Sales_data ccout(const Sales_data&name);
注:友元的声明仅仅指定了访问的权限,而非函数声明。如果希望类的用户能够调用友元函数,那么就必须在友元声明之外再进行一次函数声明。 四、C++类的特性补充 定义一个类型成员:
class Screen
{
public:
typedef string::size_type pos;
Screen() = default;
Screen(pos ht, pos wd, char c):height(ht), width(wd),contents(ht*wd,c){}
char get()const
{
return contents[cursor];
}
inline char get(pos ht, pos wd) const;
Screen &move(pos r, pos c);
private:
pos cursor = 0;
pos height = 0;
pos width = 0;
string contents;
};
书上的代码,这段代码定义了一些成员函数,默认构造函数为编译器给出。其中的get和move函数在类外进行定义,同时,get函数还是个重载函数。
inline
Screen& Screen::move(pos r, pos c)
{
pos row = r * width;
cursor = row + c;
return *this;
}
char Screen::get(pos r, pos c)const
{
pos row = r * width;
return contents[row + c];
}
可变数据成员: 如果希望修改类的某个数据成员,即使是const成员函数内的,可以使用mutable关键字来完成。一个可变数据成员永远不会是const类型,因此一个const成员函数可以改变一个可变成员的值。定义一个可变数据成员:
mutable param1;
即使是在const成员内部也可以被修改。接着定义一个类关联的窗口管理类,用来表示显示器上的一组Screen。
class Window_mag
{
private:
std::vector<Screen> screens{ Screen(24,80,' ') };
};
继续在Screen里面添加两个set函数:
Screen& Screen::set(char c)
{
contents[cursor] = c;
return *this;
}
Screen& Screen::set(pos r, pos col, char ch)
{
contents[r * width + col] = ch;
return *this;
}
注:上述的函数如果定义在类内部就不要在外部再重复定义了,可以把函数体也写在类内部。对于这一章节中的代码敲完了一遍,但是发现了其中很多的bug,希望后续学习能够解决其中的问题😥。
|