NDK1 C++基础,面向对象编程
前言
前端时间出差了一段时间封闭式开发,所以未继续学习和更新,在这说声抱歉-v-
类
Student.h 定义类
因为c++ 是面向对象的 所以可以有类;
类这里默认都是private私有的;
#pragma once 表示在预处理器的时候,保证只引入一次头文件;
析构函数:当我们对象被释放回收,就会执行析构函数,像不像Android里面的onDestroy方法?-v-
函数加上const 这个表示这是一个常量函数:不允许修改类中的成员;
友元函数:定义在类外部,有权访问类的所有私有(private)成员和保护(protected)成员,尽管友元函数的原型有在类的定义中出现过,但是友元函数并不是成员函数;
friend class 类:添加友元类之后, 这个Person就可以直接访问我们这个类里面的私有成员和函数了
//
// Created by Lenovo on 2020/11/6.
// Student.h 头文件
//
// TODO #pragma once 表示在预处理器的时候,保证只引入一次头文件
#pragma once
#include <iostream>
#ifndef NDK04_CPP_STUDENT_H
#define NDK04_CPP_STUDENT_H
#endif //NDK04_CPP_STUDENT_H
// TODO 因为c++ 是面向对象的 所以可以有类
class Student {
// 结构体默认 public
// 这里默认都是private私有的
public:
Student(); //声明构造方法
Student(int age,int age2,int age3); //声明构造方法
~Student(); //TODO 声明析构函数:当我们对象被释放回收,就会执行析构函数
private:
int age;
protected:
int age2;
public:
int age3;
public:
// TODO 加上const 这个表示这是一个常量函数
// TODO 常量函数:不允许修改类中的成员
void setAge(int age) const ;
// TODO 普通函数
void setAge2(int age2);
/**
* 关键字 friend 就是友元函数:定义在类外部,
* 但有权访问类的所有私有(private)成员和保护(protected)成员。
* 尽管友元函数的原型有在类的定义中出现过,但是友元函数并不是成员函数
*/
friend void updateField(Student *);
// TODO friend class 类,添加友元类之后, 这个Person就可以直接访问我们这个类里面的私有成员和函数了
friend class Person;
private:
int private01;
int private02;
int private03;
};
// TODO 此类想访问 Student 类的私有成员,此类必须是和Student成为好朋友
class Person{
void update(Student *student){
//因为是友元类,所以这类可以访问 私有成员了,如果不是友元类,编译出错
student->private01 = 110;
student->private02 = 1110;
}
};
自定义的日志类
#include <android/log.h> :使用 NDK 里面的日志库打印,这个日志可以和Android的Log日志一样输出打印
#define TAG “KAIZI”:定义一个宏 TAG 等于是常量,等同于Log的Tag标签;
//
// Created by Lenovo on 2020/11/6.
//
#ifndef NDK04_CPP_MYLOG_H
#define NDK04_CPP_MYLOG_H
#endif //NDK04_CPP_MYLOG_H
//TODO 使用 NDK 里面的日志库打印
#include <android/log.h>
//定义一个宏 TAG 等于是常量
#define TAG "KAIZI"
//定义自己的日志输出
#define LOGD(...) __android_log_print(ANDROID_LOG_DEBUG, TAG, __VA_ARGS__)
#define LOGE(FORMAT,...) __android_log_print(ANDROID_LOG_INFO,"Wayne",FORMAT,##__VA_ARGS__)
Student.cpp 实现类-类的普通使用
const 常量函数:不允许修改类中的成员,否则编译出错
cout << “Student” << endl;Android Studio里面不能这么写打印
//
// Created by Lenovo on 2020/11/6.
//
#include "Student.h"
#include "myLog.h" //导入了我们的日志文件
Student::Student() {
// TODO Android Studio里面不能这么写 打印
// cout << "Student" << endl;
LOGD("无参构造方法");
}
Student::Student(int age, int age2, int age3) {
this->age = age;
this->age2 = age2;
this->age3 = age3;
LOGD("有参构造");
}
//TODO 析构函数:当我们对象被释放回收,就会执行析构函数
Student::~Student() {
LOGD("析构函数");
}
// TODO 常量函数:不允许修改类中的成员
void Student::setAge(int age) const {
// this->age = age; //编译出错
}
// 普通函数
void Student::setAge2(int age2) {
this->age2 = age2;
}
/**
* 关键字 friend 就是友元函数:定义在类外部,
* 但有权访问类的所有私有(private)成员和保护(protected)成员。
* 尽管友元函数的原型有在类的定义中出现过,但是友元函数并不是成员函数
*/
void updateField(Student *student){
//因为是友元函数 所以这里可以访问了 私有成员变量
student->private01 = 99;
}
单例-头文件MyInstance.h
class 毋庸置疑,写法和java的差不多;
定义一个私有的静态的成员变量;static MyInstance * instance;
定义一个私有的构造方法;
定义一个析构函数,用来做回收操作;
定义公开的静态的获取实例的方法;
以及自定义的函数方法、释放的方法;
//
// Created by Lenovo on 2020/11/6.
//
#ifndef NDK04_CPP_MYINSTANCE_H
#define NDK04_CPP_MYINSTANCE_H
#endif //NDK04_CPP_MYINSTANCE_H
#include <iostream>
// TODO 头文件中写声明 不做实现
class MyInstance{
private:
static MyInstance * instance; //私有的静态的成员变量
MyInstance(); //私有的构造方法
~MyInstance(); //析构函数
public:
static MyInstance * getInstance(); //公开的静态的获取实例的方法
void show();
void showName();
// 释放
void unInstance();
};
单例-实现文件MyInstance.cpp
记得引入头文件 #include “MyInstance.h”;
nullptr:就是NULL;
MyInstance * -----》这一部分是返回值;
MyInstance:: 就是静态调用;
MyInstance::instance ------》这里就是类的静态(成员 或者 方法)调用,调用的是instance成员变量;
C++11之后,内部会自动保证,所有static成员变量,线程的安全问题,所以我们这getInstance方法中不需要像java一样,进行加锁一样的操作,我们这类判断了一下非空;
实现了头文件的方法,unInstance这个是我们自己定义的释放方法,所以unInstance中我们做释放和回收,delete instance,instance = nullptr;因为是new出来,new是再堆中,所以要delete ;
好了,简单的单例就写好了~~
//
// Created by Lenovo on 2020/11/6.
//
#include "MyInstance.h"
#include "myLog.h"
/**
* nullptr:就是NULL
*
* 注意:
* MyInstance * -----》这一部分是返回值
* MyInstance::instance ------》这里就是类的静态(成员 或者 方法)调用
*/
MyInstance * MyInstance::instance = nullptr;
MyInstance::MyInstance() {
LOGD("调用了MyInstance 的无参构造");
}
void MyInstance::show() {
LOGD("调用了单例里面的 show方法");
}
void MyInstance::showName() {
LOGD("调用了单例里面的 showName方法");
}
// TODO MyInstance * -----》这一部分是返回值
MyInstance* MyInstance::getInstance() {
//C++11之后,内部会自动保证,所有static成员变量,线程的安全问题
if(!instance){ // instance==null
instance = new MyInstance();
}
return instance;
}
//释放
void MyInstance::unInstance() {
if(instance){ //if(instance!=null)
delete instance;
instance = nullptr;
}
}
// TODO 析构函数 等于被回收的时候 会回调这个方法
MyInstance::~MyInstance() {
LOGD("单例被调用了 释放,进入到析构函数了 MyInstance。。。。");
}
继承的写法
Person 做父类,Student 做子类,(Student : public Person)在C++里面是可以多继承的,和java不一样;
默认是 私有继承;
如果是私有继承,是使用不了父类的属性 (包括public的属性);
如果是 : Person{ } 就是私有继承;
虚函数:是子类可以重写的该方法;virtual 关键字;
纯虚函数:等于java中的抽象方法,子类必须要重写该方法,不然编译报错;
//
// Created by Lenovo on 2020/11/10.
//
#include "myLog.h"
#include <iostream>
#ifndef NDK05_CPP_MYEXTENDS_H
#define NDK05_CPP_MYEXTENDS_H
#endif //NDK05_CPP_MYEXTENDS_H
// 父类
class Person{
private:
int age;
char sex;
public:
char *name = "kaizi";
void show(){
LOGD("Person show runing ...");
}
void show1(){
LOGD("Person show1 runing ...");
}
void show2(){
LOGD("Person show2 runing ...");
}
//虚函数,子类可以重写该方法
virtual void show3(){
LOGD("Person show3 runing ...");
}
//纯虚函数 == java中的抽象方法,子类必须要重写该方法,不然编译报错
virtual void show4() = 0;
};
class Person2{};
class Person3{};
class Person4{};
//子类
/**
* TODO 默认是 私有继承 == private Person (私有继承,只是建立父子关系)
* TODO 如果是私有继承,是使用不了父类的属性 (包括public的属性)
* TODO 如果是 : Person{ } 就是私有继承
* TODO C++可以多继承
*/
class Student2 : public Person,Person2,Person3,Person4{
public: //默认是私有,外部想调用的话,必须公开
void show(){
LOGD("Student show runing ...");
}
void show1(){
LOGD("Student show1 runing ...");
}
void show2(){
LOGD("Student show2 runing ...");
}
void show3(){
LOGD("Student show3 runing ...");
}
void show4(){
LOGD("Student show4 runing ...");
}
};
main.h 头文件-测试自定义类的方法
定义一个模拟入口,我这里入口函数名是mainTest
注意哦,这里的入口是不会自动调用的,至于调用的地方我们下面看;
//
// Created by Lenovo on 2020/11/6.
//
#ifndef NDK04_CPP_MAIN_H
#define NDK04_CPP_MAIN_H
#endif //NDK04_CPP_MAIN_H
int mainTest();
main.cpp 头文件的实现-测试自定义类的方法
我们这里来进行测试和调用上面的单例、类对象
引入了各种需要测试的头文件;
mainTest 是我们用来模拟的入口,所以从这个方法进入进行调用;
注意了解 栈中创建、堆中创建的方式(new),堆中new出来记得要delete释放;
test1、test2、test3 是各种创建对象的方式,以及创建出来的位置;
操作符重载
操作符封装:参数记得是用地址,&:取地址符号
继承的使用和注意点
如果是私有继承,是使用不了父类中的成员;
如果是 public的继承父类,是可以使用父类的公共属性和函数的;
静态多态:是在编译期,编译的时候 只看左边是谁,就调用谁的方法;
动态多态:,在运行的时候,去查看父类的的方法是否定义了虚函数,如果定义了虚函数(virtual)会执行子类重新的方法
//
// Created by Lenovo on 2020/11/6.
//
#include <iostream>
#include "main.h"
#include "Student.h"
#include "MyInstance.h"
#include "myLog.h"
#include <stdint.h>
void test1() {
Student student; //在栈中进行创建,调用 无参构造 紧接着 调用析构函数
} //函数出栈
void test2() {
// TODO 不会调用析构函数,因为new 是在堆中创建
// TODO new 出来的 是需要用指针来接收
Student *student = new Student;
// TODO new出来的引用 一定要记得释放 delete
delete student;
}
void test3() {
Student student(78, 100, 88);
}
// TODO 操作符重载==========start=====================
//运算符再类里面的
class MyOperator{
public:
int value;
// TODO operator运算符重载 +
MyOperator operator+(const MyOperator& tt){
MyOperator temp;
temp.value = this->value + tt.value;
return temp;
}
// TODO operator运算符重载 -
MyOperator operator-(const MyOperator& tt){
MyOperator temp;
temp.value = this->value + tt.value;
return temp;
}
// TODO operator运算符重载 *
MyOperator operator*(const MyOperator& tt){
MyOperator temp;
temp.value = this->value + tt.value;
return temp;
}
// TODO operator运算符重载 /
MyOperator operator/(const MyOperator& tt){
MyOperator temp;
temp.value = this->value + tt.value;
return temp;
}
};
// TODO 另一种运算符重载写在外面的写法===start==========
class MyOperator2{
public:
int count;
};
MyOperator2 operator+(MyOperator2 myOper,MyOperator2 myOper2){
MyOperator2 temp;
temp.count = myOper.count+myOper2.count;
return temp;
}
// TODO 另一种运算符重载卸载外面的写法===end==========
// TODO 特殊的一些操作符==============start=========
// TODO void * 表示返回的是任意指针类型 这一个方法是重写了new方法,参数这些都需要和父类一致才是重写
void * operator new(size_t size){
LOGD("谁new了 %d大小的空间",size);
return malloc(size);
}
// TODO 不知道会传入什么类型的指针 所以用 void * 来接收任意指针参数 可以看作是 java的 object类型
void operator delete(void * p){
LOGD("谁delete了 内存地址是:%#x",p);
}
// TODO 特殊的一些操作符==============end=========
// TODO 操作符重载==========end=====================
// 模拟入口
int mainTest() {
test1();
test2();
test3();
// TODO 使用我们自己的单例模式
MyInstance *myInstance = MyInstance::getInstance();
myInstance->showName();
myInstance->show();
// TODO 调用 我们写的释放方法 释放我们的单例对象
myInstance->unInstance();
// TODO 使用运算符重载
MyOperator myOperator;
myOperator.value = 1000;
MyOperator myOperator2;
myOperator2.value = 2000;
MyOperator myOperator3;
myOperator3 = myOperator + myOperator2;
myOperator3 = myOperator * myOperator2;
myOperator3 = myOperator - myOperator2;
myOperator3 = myOperator / myOperator2;
// 试试我们自己重写的 new操作符
MyOperator *myOperator1 = new MyOperator;
// 试试我们自己重写的 delete操作符
delete myOperator1;
//测试继承
Student2 student2;
// TODO 如果是私有继承,是使用不了父类中的成员
// TODO 如果是 public的继承父类,是可以使用父类的公共属性和函数的
student2.name ="sasa";
student2.show();
student2.show1();
// TODO 继承
// TODO 静态多态,是在编译期,编译的时候 只看左边是谁,就调用谁的方法
Person *person = new Student2;
person->show(); //调用父类的 //堆中定义的 所以 会用到 ->
// TODO 动态多态,在运行的时候,去查看父类的的方法是否定义了虚函数,如果定义了虚函数会执行子类重新的方法
person->show3();//调用子类的
delete person;
return 0;
}
调用模拟入口
通过Android调用jni的方法,然后调用了我们自己写的模拟入口
#include <jni.h>
#include <string>
#include "myCpp/main.h"
#include "myCpp/myLog.h"
using namespace std;
extern "C" JNIEXPORT jstring JNICALL
Java_com_lk_ndk04_1cpp_MainActivity_stringFromJNI(
JNIEnv* env,
jobject /* this */) {
string hello = "Hello from C++";
LOGD("AAAAAAAAAAAAAAAAAAA");
//模拟入口
mainTest();
return env->NewStringUTF(hello.c_str());
}
导入需要使用的文件
file(GLOB sourceFiles myCpp/.h myCpp/.cpp)
${sourceFiles}
批量导入myCpp目录下的.h 和 .cpp 文件
# For more information about using CMake with Android Studio, read the
# documentation: https://d.android.com/studio/projects/add-native-code.html
# Sets the minimum version of CMake required to build the native library.
cmake_minimum_required(VERSION 3.4.1)
# Creates and names a library, sets it as either STATIC
# or SHARED, and provides the relative paths to its source code.
# You can define multiple libraries, and CMake builds them for you.
# Gradle automatically packages shared libraries with your APK.
#批量导入 需要使用的文件
file(GLOB sourceFiles myCpp/*.h myCpp/*.cpp)
add_library( # Sets the name of the library.
native-lib
# Sets the library as a shared library.
SHARED
# Provides a relative path to your source file(s).
native-lib.cpp
# 引入批量导入的文件
${sourceFiles}
# myCpp/mylog.h
# myCpp/Student.cpp
# myCpp/Student.h
# myCpp/main.cpp
# myCpp/main.h
# myCpp/MyInstance.cpp
# myCpp/MyInstance.h
)
# Searches for a specified prebuilt library and stores the path as a
# variable. Because CMake includes system libraries in the search path by
# default, you only need to specify the name of the public NDK library
# you want to add. CMake verifies that the library exists before
# completing its build.
find_library( # Sets the name of the path variable.
log-lib
# Specifies the name of the NDK library that
# you want CMake to locate.
log )
# Specifies libraries CMake should link to your target library. You
# can link multiple libraries, such as libraries you define in this
# build script, prebuilt third-party libraries, or system libraries.
target_link_libraries( # Specifies the target library.
native-lib
# Links the target library to the log library
# included in the NDK.
${log-lib} )
辛苦各位童鞋观看到最后,如果博客中有不对的地方望指出,大神勿喷,谢谢~~