C++:07.类型转换、实现System.arrayCopy、异常处理

1. 类型转换

1
2
3
4
5
Student *stu = static_cast<Student*>(person); // 正确
Student stu = static_cast<Student>(person); // 错误

Student *stu = reinterpret_cast<Student*>(person); // 正确
Student stu = reinterpret_cast<Student>(person); // 错误

1.1 static_cast 静态转换

  • 非指针情况下:子类可以转换成父类,父类不能转换成子类,指针情况下可以
  • 用于基本数据类型之间的转换,如把int转换成char
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
class Person{
public:
string name;
int age;
public:
Person(string name,int age):name(name),age(age){}
};

class Student : public Person{
public:
Student(string name,int age):Person(name,age){
}
};

class Worker: public Person{
};

// static_cast(静态转换 类似于 直接转换)
int main(){
double number1 = 20.02;
// 直接转换
// int number2 = number1;
// 用于基本数据类型之间的转换,例如把 int 转 char
// int number2 = static_cast<int>(number1);
// cout << number2 << endl;

// 把类型转换成另一种类型,用于类层次结构中基类和派生类之间指针或引用的转换
// Student *stu = new Student("eastrise",26);
// Person *person = stu;
// Person *person = static_cast<Person*>(stu); // ok的

// 待会再试
Person person = Person("eastrise",26);
// 转成 Student
// Student stu = person; // 错误

cout << person.name.c_str() << " , " << person.age << endl;
}

1.2. const_cast 常量转换

用于修改常量的值(转换成了不是常量的指针然后去修改值

1
2
3
4
5
6
7
8
9
10
11
12
13
int main(){
const Person* person = new Person("eastrise",26);

cout << person->name.c_str() << " , " << person->age << endl;

// person->age = 24;
// const_cast
Person* person1 = const_cast<Person*>(person);
person1->age = 25;
person1->name = "Jack";

cout << person1->name.c_str() << " , " << person1->age << endl;
}

1.3. reinterpret_cast 强制类型转换

用于转换任意类型

  • 非指针情况下:子类可以转换成父类,父类不能转换成子类,指针情况下可以
  • jni 中常见的是 long指针
1
2
3
4
5
6
7
8
9
10
11
12
13
14
int main(){
// 待会再试
Person *person = new Person("eastrise",26);
// 转成 Student
// Student stu = person; // 错误
// Student *stu = static_cast<Student*>(person); // 正确

long mPtr = (long)person; // NDK中可以
// 除了字符类,各种类型的转换 long -> 对象的指针* ,用到reinterpret_cast
// 与 static_Cast 区别在于 static_cast 一般用于转换有继承关系的类型 reinterpret_cast 也能转换有继承关系的类型
Student *stu = reinterpret_cast<Student*>(person);

cout << stu->name.c_str() << " , " << stu->age << endl;
}

1.4. dynamic_cast 动态转换

必须要包含多态类型 ,虽然更安全转换成功返回类型,失败返回空
static_cast 很类似,但是更安全

static_cast 一般用于转换有继承关系的类型

1
2
3
4
5
int main(){
Student *stu = new Student("",26);

Person *worker = dynamic_cast<Person* >(stu);
}

2. native 层实现 System.arrayCopy 的功能

具体代码请看:NDKPractice项目的cpp21

  • jobject obj = env->GetObjectArrayElement(src_array,srcPos+i);:获取jobjectArray中下标为srcPos+i的数据。
  • env->SetObjectArrayElement(dest_array,destPos+i,obj);:设置jobjectArray中下标为destPos+i的数据为obj
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
extern "C"
JNIEXPORT void JNICALL
Java_com_darren_ndk_day26_MainActivity_arraycopy(JNIEnv *env, jclass type, jobject src, jint srcPos,
jobject dest, jint destPos, jint length) {

// 做一些列的判断 ,是不是数组
// 做一系列的准备工作 ,如果有异常,挂了,程序是会崩掉
// buggly so库报错 ,如果有抛 java 层的异常,是可以 try ,但是很多情况下并不会抛java层的异常
// 如果没抛 java 层的异常,在 java 层 try 了 依旧会蹦
// src
// dest
// 都是 java 数组,需要类型转换 reinterpret_cast static_cast dynamic_cast(最佳)
// dynamic_cast 但是必须包含多态类型
jobjectArray src_array = reinterpret_cast<jobjectArray>(src);
jobjectArray dest_array = reinterpret_cast<jobjectArray>(dest);
if(src_array && dest_array){
__android_log_print(ANDROID_LOG_ERROR,"TAG","转换成功");

// 设置值
for(int i = 0; i< length ; i ++){
jobject obj = env->GetObjectArrayElement(src_array,srcPos+i);
// 放到新数组里面
env->SetObjectArrayElement(dest_array,destPos+i,obj);
}
// 完毕
}
}

3. 异常处理

  • c++ 中有自己一套异常的体系,不要去强记 c++自己的异常
  • 但是 c++ 可以抛任何数据类型 try{}catch(数据类型 变量名){}
  • throw 抛异常
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
int main(){
// c++ 中有自己一套异常的体系,不要去强记
// 但是 c++ 可以抛任何数据类型 try{}catch(数据类型 变量名){}
// throw 抛异常
try{
int i = 0;

if(i == 0)
throw Exception("出异常了");

if(i < 0)
throw 12.5f;
} catch (int number) {
cout << "捕捉到异常" << number << endl;
} catch (Exception e) {
cout << "捕捉到异常:" << e.what() << endl;
} catch (...) {
cout << "捕捉到其它异常"<< endl;
}
}

NDK 异常总结:

  1. 在 c++ 层如果是自己写的代码或者调用别人的方法,记得要 try 住, 如果不 try 在 java 层 try 是没有意义的
  2. 如果异常需要往外抛给 java 层,一定要按照java层抛异常的方式
  3. 如果是自己写的 NDK 层的代码,最好抛自己写的异常,声明异常
  4. 如果是做 c++/c , 或者是帮 c/c++ 写代码,最好抛系统定义好的异常或者继承系统的异常
  5. 系统异常的体系 exception 基类 https://www.cnblogs.com/QG-whz/p/5136883.html
1
2
3
4
5
6
7
8
9
10
11
12
void c_method() throw(Exception,int){ // 如果是自己写的, 1000 多行
throw Exception("异常了");
}


try {
c_method();
}catch (Exception exception){
// 这个异常可以抛给 java 层,但是要抛成 java 层的异常
jclass je = env->FindClass("java/lang/Exception");
env ->ThrowNew(je,exception.what());
}

4.NDK异常处理增强

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
class Exception : public out_of_range {
public:
Exception(string mag) : out_of_range(mag) {
cout << "构造函数" << endl;
}

~Exception() {
cout << "析构函数" << endl;
}
};

void c_method() { // 如果是自己的写,1000 多行
cout << "抛异常" << endl;
throw new Exception("异常了");
}

int main() {
try {
c_method();
} catch (Exception *e) {
// Exception:多次构造函数和析构函数
// Exception&:避免了多次创建对象(最多的)
// Exception*:创建的对象会被析构,如果使用局部函数或者成员就会是一个野指针
cout << "try异常" << e->what() << endl;
delete e;
} catch (...) {
cout << "其它异常" << endl;
}
}
-------------本文结束感谢您的阅读-------------
坚持原创技术分享,您的支持将鼓励我继续创作!
0%