添加链接
link管理
链接快照平台
  • 输入网页链接,自动生成快照
  • 标签化管理网页链接

点赞关注,不再迷路,你的支持对我意义重大!

🔥 Hi,我是丑丑。本文 GitHub · Android-NoteBook 已收录,这里有 Android 进阶成长路线笔记 & 博客,欢迎跟着彭丑丑一起成长。(联系方式在 GitHub)

声明命名空间:
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() {
        // 输出:
        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、友元函数不是成员函数,但是它可以访问类中的私有成员; 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);
        // 输出:
        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 hy(T c, T &d);
    

    STL 容器

    描述
    vector动态数组
    list链表
    stack
    queue队列
    set红黑树,自动排序,无重复
    multiset红黑树,自动排序,有重复
    map红黑树,有序的键 / 值对,有重复
    multimap红黑树,有序的键 / 值对,无重复
  • 《C++ Primer Plus》—— [美] Stephen Prata 著
  • 创作不易,你的「三连」是丑丑最大的动力,我们下次见!

    分类:
    Android
    标签: