文章目录
- 1 类的动态内存分配
-
- 1.1 C++动态内存分配
- 1.2 拷贝构造函数
- 1.3 赋值运算符(operator=)重载
- 2 异常
- 3 类型转换运算符
1 类的动态内存分配
1.1 C++动态内存分配
在C/C++中都可以使用malloc
/free
来分配内存,但C++还有一种更好的方法:new
和delete
。下面以动态分配int
类型的变量为例,来看看如何使用这两个关键字:
(1)变量
int *pn = new int;
delete pn;
(2)数组
int *psome = new int[10];
delete []psome;
1.2 拷贝构造函数
拷贝构造函数是用于将一个对象复制到新创建的对象中,如果用户没有声明拷贝构造函数的话,编译器将生成一个默认的拷贝构造函数,它将逐个赋值非静态成员。它的原型如下:
Class_name(const Class_name &)
假设有一个String
类,motto
是一个String
类对象,它的拷贝构造函数为String(const String &)
,它的拷贝构造函数被调用的时机有以下几种:
String ditto(motto);
String metto = motto;
String also = String(motto);
String *pString = new String(motto)
所以如果有一个函数传的参数是String
类形参,而不是引用的话,编译器将临时使用拷贝构造函数创建一个该类的副本。假设String
类的构造函数中有分配内存,析构函数中有释放内存。此时若用户没有定义自己的拷贝构造函数,则编译器会调用默认的拷贝构造函数(而不是构造函数),而在这个函数调用完后,将调用析构函数释放内存。这就会导致一些内存错误。如下所示:
String(const String& other)
{
len = other.len;
str = new char[len + 1];
strcpy(str, other.str);
}
- 一个函数如果返回对象的引用则不会调用拷贝构造函数,否则将调用拷贝构造函数。
1.3 赋值运算符(operator=)重载
前面我们知道String metto = motto;
将调用拷贝构造函数,那什么时候调用拷贝构造函数,什么时候调用赋值运算符重载:在类定义的时候的=
调用拷贝构造函数,在类定义完后的=
调用赋值运算符重载:
调用拷贝构造函数:
String metto = motto;
调用赋值运算符重载:
String metto;
metto = motto;
与复制构造函数相似,赋值运算符的隐式实现也对成员进行逐个复制。所以对于上面的metto = motto
来说,如果metto
原本就通过动态内存分配分配了一块内存,这样隐式的拷贝就会导致之前的内存来不及释放。如下所示:
String & String::operator=(const String & st)
{
if (this == &st)
服务器托管网 return *this;
delete [] str;
len = st.len;
str = new char [len + 1];
strcpy(str, st .str) ;
return *this;
}
2 异常
C++异常是对程序运行过程中发生的异常情况的一种响应。异常提供了将控制权从程序的一个部分传递到另外一部分的途径。C++可以使用try-catch来捕获异常,直接来看一个求调和平均值2ab/(a+b)
的例子:
double hmean(double a, double b);
int main(){
double x, y, z;
std::cout > x >> y){
try{
z = hmean(x,y);
}
catch(const char * s){ // start of exception handler
std::cout
在try
块中的代码若判断出异常后,throw
一个异常(类似跳转,同时退出当前函数),就能被catch
捕获。下面再来看一下将对象用作异常类型的例子:
#include
class bad_hmean{
private:
double v1;
double v2;
public:
bad_hmean(int a = 0, int b = 0) : v1(a), v2(b) {}
void mesg();
};
inline void bad_hmean::mesg(){
std::cout > x >> y){
try { // start of try block
z = hmean(x, y);
cout
也就是说发送异常时可以throw
一个类,然后在catch
时使用bad_hmean & bh
获得这个对象的引用。
3 类型转换运算符
C语言中的强制类型转换允许几乎所有情况的转换,比如将一个指针的地址转换为char,这样就输出的是这个32位指针变量的地址的低8位(大端)。显然,这种转换是没有意义的,大概率是程序员写错了,所以C++有几种更严格的类型转换机制:
(1)dynamic_cast
用于在运行时执行安全的向下类型转换,通常用于处理多态类型的类层次结构,如继承关系。
dynamic_cast(expression)
type_name:目标类型的名称,通常是一个类或类的指针/引用类型。
expression:是要进行类型转换的表达式,通常是指向基类对象的指针或引用。
dynamic_cast
会检查是否可以安全地将 expression
转换为 type_name
类型,如果可以,它将返回一个指向目标类型的指针(或引用),否则返回一个空指针(如果转换失败)或抛出 std::bad_cast
异常(如果转换不安全)。下面看一个例子:
#include
using namespace std;
class Shape {
public:
virtual void draw() { cout(shape);
if (circle) {
circle->specialCircleFunction();
} else {
// 转换失败
}
delete shape;
return 0;
}
(2)const_cast
用于添加或去除对象的 const
限定符,以便在需要时更改对象的常量性。通常情况下,const_cast
用于修改指向 const
对象的指针或引用,以使其可以修改对象的值。但要注意,滥用 const_cast
可能会导致未定义的行为,因此应该谨慎使用。
const_cast(expression)
new_type:要转换成的类型。
expression:要进行类型转换的表达式,通常是指向const对象的指针或引用。
下面看一个例子:
#include
int main() {
const int x = 10;
const int* ptr1 = &x;
int* ptr2 = const_cast(ptr1); // 使用const_cast去除const限定符服务器托管网
*ptr2 = 30;
std::cout
(3)static_cast
用于执行编译时类型转换,可以在合理的情况下将一个类型转换为另一个相关类型,例如将整数转换为浮点数。但要注意,static_cast
不提供运行时检查,因此必须确保类型转换是安全的。
static_cast(expression)
new_type:要转换成的目标类型。
expression:要进行类型转换的表达式。
下面来看一个例子:
#include
int main() {
int integerNumber = 42;
double doubleNumber = static_cast(integerNumber);
std::cout
需要注意的是,static_cast
不执行运行时检查,因此在使用时需要谨慎,确保类型转换是安全的。如果转换不安全,可以考虑使用 dynamic_cast
或其他类型转换运算符进行更安全的类型转换。
(4)reinterpret_cast
用于执行低层的类型转换,允许你将一个指针类型转换为另一种不相关的指针类型,或者将任何类型转换为一个完全不同的类型。这是最不安全的类型转换之一,因为它不会进行任何类型检查或转换操作。
reinterpret_cast(expression)
new_type:要转换成的目标类型。
expression:要进行类型转换的表达式,通常是指针、引用或其他表达式。
下面看一个例子,这里用static_cast
的话就无法编译通过。
#include
int main()
{
int array[5] = {1, 2, 3, 4, 5};
int* ptr = array;
char* charPtr = reinterpret_cast(ptr);
std::cout (charPtr[0])
这是一个非常危险的操作,因为它忽略了数据的实际类型和结构。所以reinterpret_cast
应该非常小心地使用,只有在确切清楚这种类型转换是必要的情况下才应使用。
服务器托管,北京服务器托管,服务器租用 http://www.fwqtg.net
相关推荐: 拍摄视频的时候相机断电导致视频文件损坏,怎么修复
3-4 现在好多人都有自己的相机,但是专业用来录像的机器应该是不太可能都有的,相机的稳定性会比专业的机器差一些,如果用于比较重要的场景,比如婚庆、会议录像、家庭录像使用等,有较少的概率会出现一些奇怪的情况,最严重的服务器托管网应该就是拍出来的东西打不开了。 本…