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} )

辛苦各位童鞋观看到最后,如果博客中有不对的地方望指出,大神勿喷,谢谢~~

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值