NDK | C++ 复习笔记

简介: NDK | C++ 复习笔记

基础概念


  • 命名空间


声明命名空间:
namespace xurui {
    int age = 1;
    char * name = "xurui";
}
使用命名空间(要求放在声明之后,可以在文件头调用,也可以在函数内调用):
using namespace xurui;
访问命名空间内的成员:
xurui::name 或 name(没用冲突时,可以省略命名空间::)
复制代码
#include<iostream> // C++ 标准库
using namespace std; // 命名空间,类似于 Java 的内部类
cout<< "C++" << endl; // 引用引用了std::命名空间,所以可以省略
复制代码

提示: << 是操作符重载


  • C++ 中的 bool 类型


C 语言没有布尔类型,C++ 中的 bool 类型其实是对 int 的包装。


cout << true << endl;
输出:1
复制代码
  • C 与 C++ 中常量的区别


C:假常量
const int number = 100;
int * numP = &number;
*numP = 10000;
printf("%d\n", number); // 10000,“常量了” 被修改
C++:真常量
const int number = 100;
// 有的编译器不通过,有的可以通过但运行报错
int * numP = &number;
复制代码
  • 引用的原理


引用变量就是一个另一个变量别名,一旦把引用初始化为某个变量,就可以使用该引用名称来访问变量。


引用 vs 指针

引用很容易与指针混淆,它们之间有三个主要的不同:

  • 1、不存在空引用,引用必须连接到一块合法的内存。存在野指针 / 悬空指针,野指针(wild pointer)是未初始化过的指针,悬空指针(dangling pointer)是指向已经被释放的内存的指针;
  • 2、引用必须在创建时被初始化,指针可以在任何时间被初始化;
  • 3、一旦引用被初始化为一个对象,就不能被指向到另一个对象,指针可以在任何时候指向到另一个对象。


  • 默认形参


int add(int n1 = 0, int n2 = 1) {
}
复制代码


默认形参可以在函数声明是指定,也可以在函数定义时指定。


  • 可变参数


描述
va_list 参数列表指针 arg_ptr
va_start(arg_ptr, argN) 使参数列表指针 arg_ptr 指向函数参数列表中的第一个可选参数,argN 是位于第一个可选参数之前的固定参数
va_arg(arg_ptr, type) 返回参数列表中指针 arg_ptr 所指的参数, 返回类型为 type. 并使指针 arg_ptr 指向参数列表中下一个参数
va_end(arg_ptr) 清空参数列表, 并置参数指针 arg_ptr 无效


#include <stdarg.h>
using namespace std;
void sum(int count, ...) {
    va_list vp;
    va_start(vp, count);
    for (int index = 0; index < count; index++) {
        int number = va_arg(vp, int);
        cout << number << endl;
    }
    va_end(vp);
}
int main() {
    // 输出:
    // 1
    // 2
    // 3
    sum(3, 1, 2, 3);
    return 0;
}
复制代码
  • 函数重载: 与 C 语言不同,C++ 支持函数重载


需要注意,如果你定义了带默认形参的函数,需要确认没有参数更少的重载函数,否则会报错:Call to 'add' is ambiguous。例如:


int add(int n1){
    return n1;
}
int add(int n1 = 1,int n2 = 1){
    return n1 + n2;
}
int main(){
    add(1); (X)// Call to 'add' is ambiguous
}
复制代码
  • 运算符重载:


重载的运算符是带有特殊名称的函数,函数名是由关键字 operator 和其后要重载的运算符符号构成的。与其他函数一样,重载运算符有一个返回类型和一个参数列表。


Student .h:
class Student {
public:
    Student operator+(Student student);
};
Student .cpp:
Student Student::operator+(Student student) {
    return Student();
}
----------------------------------------------
更严格的写法:
class Student {
public:
    Student operator+(const Student &student);
};
注意:如果没有使用 &,函数调用时会额外构建一个对象副本(拷贝构造函数)
Student Student::operator+(const Student &student) {
    return Student();
}
复制代码


类与对象


  • 类声明的规范

使用头文件 .h 声明类成员,使用 .cpp 实现类成员。这是 C++ 类定义的规范。目的是在公开 so 库时,只需要向客户端提供 .h 头文件就可以调用 so 库内的实现。


  • 声明类

Student.h


class Student {
// 私有成员
private:
    char*name;
    int age;
};
复制代码
  • 实现类

Student.cpp


class Student {
public:
    char *getName() const;
    void setName(char *name);
    int getAge() const;
    void setAge(int age);
// 私有成员
private:
    char*name;
    int age;
};
复制代码

Student.cpp


char *Student::getName() const {
    return name;
}
void Student::setName(char *name) {
    Student::name = name; // 或 this->name = name;
}
int Student::getAge() const {
    return age;
}
void Student::setAge(int age) {
    Student::age = age; // 或 this->age = age;
}
复制代码

提示:Student.cpp 编辑页面按下Alt+insert,可以选择自动插入 setter/getter 等函数


  • 对象的静态开辟和动态开辟


静态开辟:栈
Student student; // 未调用构造函数
student.setAge(10);
student.setName("mark");
cout << "name:" << student.getAge() << ",name:" << student.getName() << endl;
Student student2("Amy") // 会调用构造函数
// 函数出栈是会隐式调用 delete
动态开辟:堆
Student *student = new Student(); // 会调用构造函数
student->setAge(10);
student->setName("mark");
cout << "name:" << student->getAge() << ",name:" << student->getName() << endl;
if (student) {
    delete student; // new 分配的空间用 delete
    student = NULL; // 防止存现悬空指针
    // free(student); // (X) malloc 分配的空间用 free
}
复制代码

注意: new 分配的空间用 delete,malloc 分配的空间用 free。malloc 不会调用构造函数,free 不会调用析构函数。


  • 构造函数 & 析构函数


声明
class Student {
public:
    Student();
    Student(char*name);
    ~Student();
};
----------------------------------------------
// 调用另一个重载构造函数
Student::Student() : Student("mark") {
}
Student::Student(char *name) {
    this->name = (char *) (malloc(sizeof(char) * 10));
    strcpy(this->name, name);
}
Student::~Student() {
    // 必须释放构造器中开辟的堆区成员
    if (this->name) {
        free(this->name);
        this->name = NULL;
    }
}
复制代码

提示: new 会调用构造函数,delete会调用析构函数。


  • 拷贝构造函数


1、当类中没有定义任何构造函数时,编译器会默认提供一个无参构造函数且其函数体为空; 2、当类中没有定义拷贝构造函数时,编译器会默认提供一个拷贝构造函数,进行成员变量之间的拷贝。(这个拷贝操作是浅拷贝)。 3、调用一次构造函数,调用一次默认拷贝构造函数(浅拷贝),两个对象的指针成员所指同一块内存。调用两次析构函数,内存空间重复释放导致奔溃。


情况 1:指针赋值,没有调用拷贝构造函数
Student* student1 = new Student();
Student* student2 = student1;
情况 2:隐式调用拷贝构造函数
Student student1;
Student student2 = student1; 
情况 3:不会调用自定义的拷贝构造函数,但会调用默认拷贝构造函数
Student student1;
Student student2; 
student2 = student1; 
复制代码

提示: struct 也有类似的浅拷贝。


  • 静态成员1、可以使用 类名:: 直接访问静态成员(字段/函数) 2、静态字段需要声明与实现; 3、静态成员只能访问静态成员。


Student.h


class Student {
public:
    1、先声明静态成员:
    static int id;
    static void update(){
        id = 2;
    }
};
复制代码

Student.cpp

2、再实现静态成员(必须):
int Student::id = 1;
复制代码
Student student;
cout << student.id << endl;
Student::update();
cout << student.id << endl;
输出:
1
2
复制代码
  • 友元函数


1、友元函数是在类中声明,在类外部实现的函数; 2、友元函数不是成员函数,但是它可以访问类中的私有成员; 3、友元函数一定程度上破坏了类的封装性。


Student.h


class Student {
public:
    friend void setAge(Student * student,int age);
private:
    int age;
};
复制代码

main.cpp


void setAge(Student *student, int age) {
    student->age = age;
}
int main() {
    Student student;
    setAge(&student, 1);
    // 输出:
    // 1
    cout<<student.getAge()<<endl;
    return 0;
}
复制代码
  • 友元类友元类的所有成员函数都是另一个类的友元函数,都可以访问另一个类中的隐藏信息(包括私有成员和保护成员)。


class ImageView {
private:
    int viewSize;
    friend class Class; // 友元类
};
class Class {
public:
    ImageView imageView;
    void changeViewSize(int size) {
        imageView.viewSize = size; // 如果不声明友元类 “friend class Class”,无法访问
    }
};
复制代码

思考: 在 Java 中,私有成员无法直接访问,但是使用 Class#getDeclareField() 却可以访问,底层原理是不是 C++ 友元类?


  • 继承


class Rectangle: public Shape, public PaintCost
{
   public:
      int getArea()
      { 
         return (width * height); 
      }
};
复制代码


多继承有二义性,会导致程序不够健壮,所以 Java 的设计里面中不支持多继承。在 C++ 中,因为存在多继承,所以在开发过程中要主动避免程序二义性。如果已经出现二义性的场景,有两种解决方案: 1、可以使用类名::变量名显性访问来规避二义性; 2、使用虚继承;


  • 继承类型

当一个类派生自基类,该基类可以被继承为 public、protected 或 private 几种类型。使用 public 继承,不同继承类型规则:


1、公有继承(public):当一个类派生自公有基类时,基类的公有成员也是派生类的公有成员,基类的保护成员也是派生类的保护成员,基类的私有成员不能直接被派生类访问,但是可以通过调用基类的公有和保护成员来访问。 2、保护继承(protected): 当一个类派生自保护基类时,基类的公有和保护成员将成为派生类的保护成员。 3、私有继承(private):当一个类派生自私有基类时,基类的公有和保护成员将成为派生类的私有成员。


  • 虚继承

为了解决多继承时的命名二义性和冗余数据问题,C++ 设计出虚继承,使得在派生类中只保留一份间接基类的成员。


// 间接基类A
class A{
protected:
    int m_a;
};
// 直接基类B
class B: virtual public A{  // 虚继承
protected:
    int m_b;
};
// 直接基类C
class C: virtual public A{  // 虚继承
protected:
    int m_c;
};
复制代码
  • 多态

C++ 默认关闭多态(或者说是静态多态 / 静态链接):函数调用在程序执行前就确定了。如果要开启多态,需要在 父类 函数上声明virtual(声明为虚函数)。


  • 纯虚函数

C++ 接口没有直接的抽象类 / 接口的概念,但是可以使用纯虚函数来达到类似的语义。纯虚函数声明如下:


virtual void funtion1()=0;
复制代码


纯虚函数用来规范派生类的行为,即接口,纯虚函数一定没有定义。包含纯虚函数的类是抽象类,抽象类不能定义实例,但可以声明指向实现该抽象类的具体类的指针或引用。


模板(类似泛型)

  • 函数模板
template <class T> void swap(T& a, T& b){
}
复制代码
  • 类模板
template<class T> class A{
public: 
T a; 
T b; 
T hy(T c, T &d);
};
复制代码



STL 容器

描述
vector 动态数组
list 链表
stack
queue 队列
set 红黑树,自动排序,无重复
multiset 红黑树,自动排序,有重复
map 红黑树,有序的键 / 值对,有重复
multimap 红黑树,有序的键 / 值对,无重复


目录
相关文章
|
4天前
|
Java 编译器 C++
C++入门指南:类和对象总结笔记(下)
C++入门指南:类和对象总结笔记(下)
32 0
|
4天前
|
存储 编译器 C语言
C++入门: 类和对象笔记总结(上)
C++入门: 类和对象笔记总结(上)
36 0
|
4天前
|
设计模式 安全 编译器
Effective C++55 笔记
Effective C++55 笔记
26 0
|
7月前
|
消息中间件 存储 前端开发
[笔记]C++并发编程实战 《四》同步并发操作(三)
[笔记]C++并发编程实战 《四》同步并发操作(三)
|
4天前
|
安全 Java 程序员
【C++笔记】从零开始认识继承
在编程中,继承是C++的核心特性,它允许类复用和扩展已有功能。继承自一个基类的派生类可以拥有基类的属性和方法,同时添加自己的特性。继承的起源是为了解决代码重复,提高模块化和可维护性。继承关系中的类形成层次结构,基类定义共性,派生类则根据需求添加特有功能。在继承时,需要注意成员函数的隐藏、作用域以及默认成员函数(的处理。此外,继承不支持友元关系的继承,静态成员在整个继承体系中是唯一的。虽然多继承和菱形继承可以提供复杂的设计,但它们可能导致二义性、数据冗余和性能问题,因此在实际编程中应谨慎使用。
18 1
【C++笔记】从零开始认识继承
|
4天前
|
编译器 C语言 C++
C++入门指南:类和对象总结笔记(中)
C++入门指南:类和对象总结笔记(中)
50 0
|
4天前
|
机器学习/深度学习 算法 编译器
【C++】自学终极笔记
【C++】自学终极笔记
152 0
|
4天前
|
存储 算法 C++
《C++ STL开发技术引导》 第五章-C++ STL泛化技术分析笔记
《C++ STL开发技术引导》 第五章-C++ STL泛化技术分析笔记
|
4天前
C++2.0(C++11) 笔记 二
C++2.0(C++11) 笔记 二
25 0
|
4天前
|
编译器 容器
C++11 (C++2.0)笔记 一
C++11 (C++2.0)笔记 一
35 0