C++_day3

目录

[1. 类和对象(重点)](#1. 类和对象(重点))

[1.1 类的定义](#1.1 类的定义)

[1.2 创建对象](#1.2 创建对象)

[2. 封装(重点)](#2. 封装(重点))

[3. 构造函数 constructor(重点)](#3. 构造函数 constructor(重点))

[3.1 基础使用](#3.1 基础使用)

[3.2 构造初始化列表](#3.2 构造初始化列表)

[3.3 构造函数的调用方式(掌握)](#3.3 构造函数的调用方式(掌握))

[3.4 拷贝构造函数](#3.4 拷贝构造函数)

[3.4.1 概念](#3.4.1 概念)

[3.4.2 浅拷贝](#3.4.2 浅拷贝)

[3.4.3 深拷贝](#3.4.3 深拷贝)

[4. 析构函数 destructor(重点)](#4. 析构函数 destructor(重点))

[5. 作用域限定符 ::](#5. 作用域限定符 ::)

[5.1 名字空间(掌握)](#5.1 名字空间(掌握))

[5.2 类内声明,类外定义(重点)](#5.2 类内声明,类外定义(重点))

[5.3 配合静态使用](#5.3 配合静态使用)

[6. this关键字](#6. this关键字)

[6.1 概念(掌握)](#6.1 概念(掌握))

[6.2 调用成员(掌握)](#6.2 调用成员(掌握))

[6.3 区分重名的成员变量与局部变量(掌握)](#6.3 区分重名的成员变量与局部变量(掌握))

[6.4 链式调用(熟悉)](#6.4 链式调用(熟悉))

[7. static关键字](#7. static关键字)

[7.1 静态局部变量(掌握)](#7.1 静态局部变量(掌握))

[7.2 静态成员变量(掌握)](#7.2 静态成员变量(掌握))

[7.3 静态成员函数(掌握)](#7.3 静态成员函数(掌握))

[7.4 单例模式(了解)](#7.4 单例模式(了解))

[8. const关键字](#8. const关键字)

[8.1 修饰成员函数(掌握)](#8.1 修饰成员函数(掌握))

[8.2 修饰对象(掌握)](#8.2 修饰对象(掌握))

[8.3 修饰成员变量(掌握)](#8.3 修饰成员变量(掌握))

[8.4 修饰局部变量](#8.4 修饰局部变量)

[8.5 constexpr 常量表达式(熟悉)](#8.5 constexpr 常量表达式(熟悉))


编程语言是一直在发展的,发展历程:

机器语言 → 汇编语言 → 高级语言 → 面向对象语言 → ......

本章主要讲解面向对象编程中最基础的概念。

1. 类和对象(重点)

类:是一个抽象的概念,用于描述同一类对象的特征。在现在学习阶段,一个单独的类没有任何功能。

对象:根据类的描述创造的实体。

1.1 类的定义

类中主要包含两部分:

  • 属性 property成员变量 member value或 数据成员)

在类中存在的变量,用于存储数据,通常是一个名词,例如身高、价格、颜色......

  • 行为(成员函数 member function

可以执行的功能,是类中的函数,通常是一个动词或动词词组,例如:吃饭、运行、关闭......

成员 = 成员变量 + 成员函数

【例子】定义一个手机类。

cpp 复制代码
#include <iostream>

using namespace std;

/**
 * @brief The MobilePhone class
 * 手机类
 */
class MobilePhone // 帕斯卡(大驼峰)命名法:所有单词首字母大写
{
public: // 表示访问不受限
    string brand; // 品牌
    string model; // 型号
    int weight; // 重量

    void play_music()
    {
        cout << "Remedy" << endl;
    }

    void run_game()
    {
        cout << "炉石传说" << endl;
    }

    void communicate()
    {
        cout << "喂?" << endl;
    }

};

1.2 创建对象

C++支持两种对象:

  • 栈内存对象

在生命周期(生命周期为所在的{})结束后,自动被回收,调用成员使用.

  • 堆内存对象

必须使用new关键字创建对象,使用指针保存对象首地址,使用delete销毁对象,如果创建后没有手动销毁,对象会持续存在(内存泄漏),调用成员使用->(在Qt Creator中按.键自动转为->)

cpp 复制代码
#include <iostream>

using namespace std;

class MobilePhone
{
public:
    string brand;
    string model;
    int weight;

    void play_music()
    {
        cout << "Remedy" << endl;
    }

    void run_game()
    {
        cout << "炉石传说" << endl;
    }

    void communicate()
    {
        cout << "喂?" << endl;
    }

};

int main()
{
    // 栈内存对象
    MobilePhone mp1;
    // 调用成员变量,先赋值,再读取输出
    mp1.brand = "苹果";
    mp1.model = "16 Pro Max";
    mp1.weight = 200;
    cout << mp1.brand << endl;
    cout << mp1.model << endl;
    cout << mp1.weight << endl;
    // 调用成员函数
    mp1.communicate();
    mp1.play_music();
    mp1.run_game();

    // 堆内存对象
    MobilePhone* mp2 = new MobilePhone;
    mp2->brand = "华为";
    mp2->model = "非凡大师xt1";
    mp2->weight = 301;
    cout << mp2->brand << endl;
    cout << mp2->model << endl;
    cout << mp2->weight << endl;
    mp2->communicate();
    mp2->play_music();
    mp2->run_game();
    delete mp2; // 销毁mp2
    // 不要销毁后还使用
//    cout << mp2->brand << endl;
//    mp2->communicate();

    return 0;
} // mp1销毁

2. 封装(重点)

上面的代码与结构体非常相似,因为结构体就是一种完全开放的类。类通常需要进行封装,封装指的是先将类的一些属性和细节隐藏,再重新提供外部调用接口。

cpp 复制代码
#include <iostream>

using namespace std;

class MobilePhone
{
private: // 私有:被修饰的成员只能在类内访问
    string brand; // 读写
    string model = "16"; // 只读
    int weight; // 只写

public:
    string get_brand() // getter:读函数
    {
        return brand;
    }

    void set_brand(string b) // setter:写函数
    {
        brand = b;
    }

    string get_model()
    {
        return model;
    }

    void set_weight(int w)
    {
        weight = w;
    }
};

int main()
{
    MobilePhone mp1;
    // 调用setter设置属性值
    mp1.set_brand("华为");
    mp1.set_weight(300);
    // 调用getter获取属性值
    cout << mp1.get_brand() << endl;
    cout << mp1.get_model() << endl;

    // TODO 可以试试堆内存对象

    return 0;
}

封装的意义在于让程序员站在外部视角看待整个对象整体,忽略内部细节,同时可以提升代码的安全性和可维护性。

3. 构造函数 constructor(重点)

3.1 基础使用

类中有一种特殊的成员函数,在创建对象时必须调用,这个函数就是构造函数,构造函数的特殊性体现在:

  • 不写返回值
  • 函数名称必须是类名
  • 如果程序员不手动编写构造函数,编译器会自动添加一个无参且函数体为空的构造函数。

构造函数经常用于在创建对象时进行对象属性初始化,构造函数也支持参数默认值和重载。

cpp 复制代码
#include <iostream>

using namespace std;

class MobilePhone
{
private:
    string brand;
    string model;
    int weight;

public:
    // 编译器会在程序员不写的情况下添加下面的构造函数
//    MobilePhone(){}

    MobilePhone()
    {
        // 给属性赋予初始值
        brand  = "山寨";
        model = "???";
        weight  = 188;
        cout << "构造函数" << endl;
    }

    MobilePhone(string b,string m,int w)
    {
        brand = b;
        model = m;
        weight = w;
        cout << "构造函数2" << endl;
    }

    /**
     * @brief show 输出所有属性值
     */
    void show()
    {
        cout << brand << endl;
        cout << model << endl;
        cout << weight << endl;
    }
};

int main()
{
    MobilePhone mp1;
    mp1.show();

    MobilePhone* mp2 = new MobilePhone;
    mp2->show();
    delete mp2;

    MobilePhone mp3("魅族","Lucky08",199);
    mp3.show();

    MobilePhone* mp4 = new MobilePhone("小米","su7",2100000);
    mp4->show();
    delete mp4;

    cout << "主函数结束" << endl;
    return 0;
}

3.2 构造初始化列表

在当前阶段,下面的两种写法是等效。

3.3 构造函数的调用方式(掌握)

构造函数可以显式调用,也可以隐式调用。

显式调用:在创建对象时使用明确的构造函数调用语法,不能被explicit关键字影响。

隐式调用:在创建对象时不使用明确的构造函数调用语法,受到explicit关键字影响。

cpp 复制代码
#include <iostream>

using namespace std;

class Student
{
private:
    string name;

public:
    Student(string n):name(n)
    {
        cout << "构造函数,name=" << name << endl;
    }

    string get_name()
    {
        return name;
    }
};


int main()
{
    Student s1("张三");
    cout << s1.get_name() << endl;

    Student* s2 = new Student("李四");
    cout << s2->get_name() << endl;
    delete s2;

    string name = "王五";
    Student s3 = name; // 编译器帮忙调用了构造函数
    cout << s3.get_name() << endl;

    Student s4(name); // 编译器帮忙调用了构造函数
    cout << s4.get_name() << endl;

    return 0;
}

使用explicit关键字可以屏蔽隐式调用的构造函数。

cpp 复制代码
#include <iostream>

using namespace std;

class Student
{
private:
    string name;

public:
    // 明确的
    explicit Student(string n):name(n)
    {
        cout << "构造函数,name=" << name << endl;
    }

    string get_name()
    {
        return name;
    }
};


int main()
{
    Student s1("张三"); // 显式
    cout << s1.get_name() << endl;

    Student* s2 = new Student("李四"); // 显式
    cout << s2->get_name() << endl;
    delete s2;

    string name = "王五";
//    Student s3 = name; // 隐式,被explicit屏蔽
//    cout << s3.get_name() << endl;

    Student s4(name); // 显式
    cout << s4.get_name() << endl;

    return 0;
}

3.4 拷贝构造函数

3.4.1 概念

如果程序员不手动编写拷贝构造函数,编译器会为每个类增加一个拷贝构造函数。

通过拷贝构造函数创建的新对象,只是属性值与源对象相同,但是会在新的地址空间进行开辟。

cpp 复制代码
#include <iostream>

using namespace std;

class Student
{
private:
    string name;

public:
    Student(string n):name(n)
    {
        cout << "构造函数,name=" << name << endl;
    }

    // 编译器自动添加的拷贝构造函数
//    Student(const Student& s)
//    {
//        name = s.name;
//    }


    Student(const Student& s)
    {
        name = s.name;
        cout << "拷贝构造函数" << endl;
    }

    string get_name()
    {
        cout << &name << endl;
        return name;
    }
};


int main()
{
    Student s1("张三");
    cout << s1.get_name() << endl;

    Student s2(s1);
    cout << s2.get_name() << endl;

    return 0;
}

3.4.2 浅拷贝

当类中的成员变量出现指针时,默认的拷贝构造函数会出现浅拷贝的现象。

cpp 复制代码
#include <iostream>
#include <string.h> // 头文件

using namespace std;

class Student
{
private:
    char* name;

public:
    Student(char* n):name(n)
    {
        cout << "构造函数" <<  endl;
    }

    char* get_name()
    {
        return name;
    }
};


int main()
{
    char name[20] = "张三";

    Student s1(name);
    Student s2(s1);

    strcpy(name,"李四");

    cout << s1.get_name() << endl; // 李四
    cout << s2.get_name() << endl; // 李四

    return 0;
}

在上面的代码中,在31行修改了26行的字符数组内容,s1和s2隐藏的成员变量的值就变了,且s1和s2的name保存的地址就是26行的name,这都不符合面向对象的特性。

3.4.3 深拷贝

深拷贝的思路是在浅拷贝每次对指针进行赋值时,都单独开辟一块内存给要赋值的变量。

cpp 复制代码
#include <iostream>
#include <string.h> // 头文件

using namespace std;

class Student
{
private:
    char* name;

public:
    Student(char* n):name(new char[20])
    {
        // 同步两块内存的内容
        strcpy(name,n);
        cout << "构造函数" <<  endl;
    }

    Student(const Student& s)
    {
        // 同步两块内存的内容
        name = new char[20];
        strcpy(name,s.name);
        cout << "拷贝构造函数" << endl;
    }


    char* get_name()
    {
        return name;
    }
};


int main()
{
    char name[20] = "张三";

    Student s1(name);
    Student s2(s1);

    strcpy(name,"李四");

    cout << s1.get_name() << endl; // 张三
    cout << s2.get_name() << endl; // 张三

    return 0;
}

在上面的深拷贝代码中,new出来的空间并没有delete回收,因此会造成内存泄漏问题。

4. 析构函数 destructor(重点)

析构函数是与构造函数对立的函数,也是一种特殊的成员函数。

|--------------|---------------|
| 构造函数 | 析构函数 |
| 函数名称为类名 | 函数名称为**~类名** |
| 功能为创建对象并初始化 | 功能为在对象销毁时回收资源 |
| 在创建对象时调用 | 在对象销毁时自动被调用 |
| 有参数,支持重载和默认值 | 无参数,不支持重载和默认值 |

程序员不手写析构函数,编译器也会添加一个下面格式的析构函数:

cpp 复制代码
~类名(){}
cpp 复制代码
#include <iostream>

using namespace std;

class Dog
{
public:
    ~Dog()
    {
        cout << "析构函数" << endl;
    }
};


int main()
{
    Dog d1;
    Dog* d2 = new Dog;
    delete d2; // d2输出:析构函数

    cout << "主函数结束" << endl;
    return 0;
} // d1输出:析构函数

回到深拷贝代码中,可以在析构函数里释放堆内存资源,在Student中添加下面的代码:

5. 作用域限定符 ::

5.1 名字空间(掌握)

名字空间是一种代码的层级划分。

cpp 复制代码
#include <iostream>

using namespace std;
// C++课程中几乎所有的类型(不包括基本数据类型)都在std中

int a = 1;

// 新建一个名字空间
namespace my_space {
    int a = 3;
    string s = "哈哈哈";
}

namespace my_space2 {
    int a = 4;
    string s = "嘿嘿嘿";
}

// 使用自己的名字空间
using namespace my_space2;


int main()
{
    int a = 2;
    std::cout << "你好" << std::endl;
    cout << a << endl; // 2
    cout << ::a << endl; // 1

    // 访问my_space的内容
    cout << my_space::a << my_space::s << endl;
    // 访问my_space2的内容
    cout << my_space2::a << s << endl;

    return 0;
}

5.2 类内声明,类外定义(重点)

函数是可以声明定义分离的,成员函数也可以声明定义分离,把成员函数的声明放置在类内,把成员函数的定义放置在类外,因为定义在类外,所以需要类名:: 来制定定义的函数是哪个类的。

cpp 复制代码
#include <iostream>

using namespace std;

class Student
{
private:
    string name;

public:
    // 类内声明
    Student(string n);
    string get_name();
    void set_name(string n);
};

// 类外定义
Student::Student(string n)
{
    name = n;
}

string Student::get_name()
{
    return name;
}

void Student::set_name(string n)
{
    name = n;
}

int main()
{
    Student s("张三");
    s.set_name("张三丰");
    cout << s.get_name() << endl;

    return 0;
}

5.3 配合静态使用

在后续static关键字中讲解。

6. this关键字

6.1 概念(掌握)

this在类中表示一个指针:this指针,是一种特殊的指针,保存了当前类对象的首地址(指向了当前类的对象)。

cpp 复制代码
#include <iostream>

using namespace std;

class Student
{
private:
    string name;

public:
    Student(string n):name(n)
    {
        cout << this << endl;
    }

    string get_name()
    {
        cout << this << endl;
        return name;
    }

    void set_name(string n)
    {
        cout << this << endl;
        name = n;
    }
};



int main()
{
    Student s("张三");
    cout << &s << endl;
    s.set_name("张三丰");
    cout << s.get_name() << endl;

    cout << endl;

    Student* s2 = new Student("李四");
    cout << s2 << endl;
    cout << s2->get_name() << endl;

    return 0;
}

6.2 调用成员(掌握)

结论:成员必须由对象调用。

cpp 复制代码
#include <iostream>

using namespace std;

class Student
{
private:
    string name;

public:
    Student(string n)
    {
        this->name = n;
        cout << this->get_name() << endl;
    }

    string get_name()
    {
        return this->name;
    }

    void set_name(string n)
    {
        this->name = n;
    }
};

上面的代码中,所有在类内调用成员的位置,如果程序员不写this指针(实际上没有必要手写,比较繁琐),编译器都会在成员调用之前添加this指针。

6.3 区分重名的成员变量与局部变量(掌握)

cpp 复制代码
#include <iostream>

using namespace std;

class Student
{
private:
    string name;

public:
    Student(string name)
    {
        this->name = name;
    }

    string get_name()
    {
        return name;
    }

    void set_name(string name)
    {
        this->name = name;
    }
};



int main()
{
    Student s("Tom");
    cout << s.get_name() << endl;
    s.set_name("Jerry");
    cout << s.get_name() << endl;

    return 0;
}

6.4 链式调用(熟悉)

结论:如果一个成员函数的返回值是当前类型的引用,说明这个函数支持链式调用,return的内容一定是*this。

cpp 复制代码
#include <iostream>

using namespace std;

class Value
{
private:
    int value;

public:
    Value(int value)
    {
        this->value = value;
    }

    Value& add(int value)
    {
        this->value += value;
        return *this;
    }

    int get_value()
    {
        return value;
    }
};



int main()
{
    Value v1(0);
    // 普通的调用方式:分步操作
    v1.add(1);
    v1.add(2);
    v1.add(4);
    v1.add(7);
    cout << v1.get_value() << endl; // 14

    cout << endl;

    Value v2(0);
    // 链式调用
    cout << v2.add(1).add(2).add(4).add(7).get_value() << endl; // 14
    cout << v2.get_value() << endl; // 14

    return 0;
}

7. static关键字

7.1 静态局部变量(掌握)

使用static修饰的局部变量就是静态局部变量,所在的函数第一次被调用时创建,直到程序运行结束销毁,所有的对象共用这个一个静态局部变量。

cpp 复制代码
#include <iostream>

using namespace std;

class Test
{
public:
    void test_static()
    {
        int a = 1;
        static int b = 1; // 局部静态变量
        cout << a++ << endl;
        cout << b++ << endl << endl;
    }
};

int main()
{
    Test t1;
    Test t2;
    t1.test_static();
    t2.test_static();
    t1.test_static();

    return 0;
}

7.2 静态成员变量(掌握)

使用是static关键字修饰的成员变量就是静态成员变量。

静态成员变量具有以下特点:

  1. 非const修饰的静态成员变量不能在类内初始化,必须在类外初始化。

  2. 同一个类的所有对象共享一份静态成员变量。

  3. 静态成员变量可以直接通过类名调用,无需关联任何对象,因为静态成员变量在程序执行时创建,在程序结束时销毁。

cpp 复制代码
#include <iostream>

using namespace std;

class Test
{
public:
    int a = 1; // 成员变量
    static int b; // 静态成员变量
};

int Test::b = 1; // 类外初始化

int main()
{
    // 通过类名直接调用静态成员变量
    cout << Test::b << " " << &Test::b << endl;

    Test t1;
    Test t2;
    cout << t1.a++ << " " << &t1.a << endl;
    cout << t2.a++ << " " << &t2.a << endl;
    cout << t1.b++ << " " << &t1.b << endl;
    cout << t2.b++ << " " << &t2.b << endl;

    return 0;
}

7.3 静态成员函数(掌握)

使用static修饰的成员函数就是静态成员函数,静态成员函数具有以下特点:

  1. 没有this指针,因此不能调用非静态成员。

  2. 如果静态成员函数声明与定义分离,static只需要写在声明处即可。

  3. 除了可以使用对象调用外,还可以直接通过类名::调用,更加推荐后者。

cpp 复制代码
#include <iostream>

using namespace std;

class Test
{
public:
    int a = 1;
    static int b;

    static void func(); // 静态成员函数
};

int Test::b = 1;

void Test::func() // 类外定义
{
//        cout << a << endl; 错误
    cout << b << endl;
}

int main()
{
    Test t;
    t.func();

    Test::func();

    return 0;
}

7.4 单例模式(了解)

模式设计(Design pattern)是一套被反复使用、多数人知晓的、经过分类编目的、代码设计经验的总结。

单例 = 单实例

实例 instance = 对象 object

单例模式可以让类的对象全局创建时保持一个。

基于指针的单例模式(非完全版):

cpp 复制代码
#include <iostream>

using namespace std;

/**
 * @brief The Singleton class 单例模式的类
 */
class Singleton
{
private: // 构造函数私有化防止外部调用
    Singleton(){}
    Singleton(const Singleton&){}

    static Singleton* instance; // 类内的对象,即单例

public:
    static Singleton* get_instance()
    {
        if(instance == NULL)
            instance = new Singleton;
        return instance;
    }
};

Singleton* Singleton::instance = NULL;


int main()
{
    Singleton* s1 = Singleton::get_instance();
    cout << s1 << endl;
    Singleton* s2 = Singleton::get_instance();
    cout << s2 << endl;

    return 0;
}

基于引用的单例模式:

cpp 复制代码
#include <iostream>

using namespace std;

/**
 * @brief The Singleton class 单例模式的类
 */
class Singleton
{
private: // 构造函数私有化防止外部调用
    Singleton(){}
    Singleton(const Singleton&){}

public:
    static Singleton& get_instance()
    {
        static Singleton instance;
        return instance;
    }
};

int main()
{
    Singleton& s1 = Singleton::get_instance();
    Singleton& s2 = Singleton::get_instance();
    cout << &s1 << " " << &s2 << endl;

    return 0;
}

8. const关键字

8.1 修饰成员函数(掌握)

const修饰的成员函数,表示常成员函数,可以调用非const的成员变量,但是不能修改数值,不能调用非const的成员函数。

如果常成员函数的声明与定义分离,const在声明和定义处都要使用。

cpp 复制代码
#include <iostream>

using namespace std;

class Test
{
private:
    string name;
public:
    void set_name(string name)
    {
        this->name = name;
    }

    string get_name() const; // 常成员函数

    void test_const() const // 常成员函数
    {
//        set_name("哈哈哈"); 错误
        cout << get_name() << endl;
        cout << name << endl;
//        name = "你好"; 错误
    }
};

string Test::get_name() const // 类外定义
{
    return name;
}

int main()
{
    Test t;
    t.set_name("再见");
    t.test_const();

    return 0;
}

建议只要成员函数不修改属性值就使用const修饰,以提升代码的安全性,例如getter等。

8.2 修饰对象(掌握)

const修饰对象表示该对象是常量对象,这样的对象的成员变量数值不可变,不能调用任何非const修饰的成员函数。

cpp 复制代码
#include <iostream>

using namespace std;

class Test
{
public:
//    string name = "张三"; // 直接初始化可以

    string name;

//    Test(string name)
//    {
//        this->name = name; // 构造函数函数体初始化可以
//    }

    Test(string name):name(name){}

    void set_name(string name)
    {
        this->name = name;
    }

    string get_name() const
    {
        return name;
    }
};



int main()
{
    // const可以放在类型前后
    Test const t1("张三");
//    t1.set_name("你好"); 错误
    const Test t2("李四");
//    t2.name = "你好"; 错误
    cout << t1.get_name() << endl;
    cout << t2.get_name() << endl;

    return 0;
}

8.3 修饰成员变量(掌握)

const修饰的成员变量表示常成员变量,这样的成员变量值不允许被修改。

常成员变量的初始化方式有两种:

  • 直接初始化
  • 构造初始化列表(优先级更高)
cpp 复制代码
#include <iostream>

using namespace std;

class Test
{
public:

    const string name = "张三"; // 直接初始化

    Test(string name):name(name) // 构造初始化列表
    {}

//    Test(string name)
//    {
//        this->name = name; 错误
//    }

    void set_name(string name)
    {
//        this->name = name; 错误
    }

    string get_name() const
    {
        return name;
    }
};


int main()
{
    Test t("王五");
    cout << t.get_name() << endl;

    return 0;
}

8.4 修饰局部变量

表示局部变量不可被修改,常见于const修饰引用参数。

代码略。

8.5 constexpr 常量表达式(熟悉)

constexpr是比const更严谨的关键字,表示编译期确定的常量值。

cpp 复制代码
#include <iostream>

using namespace std;

class Test
{
public:
    constexpr static int a = 1; // a=1在编译期确定
//    constexpr int b = 2; 错误
    const int c = 3;
};

在上面的例子中,a不需要配合任何对象使用,而对象是在程序运行期间创建的,因此a可以被constexpr修饰,表示在编译期确定;反之b需要在对象创建之后才能创建,因此不能被constexpr修饰。

被constexpr修饰的内容表示在编译期间可以确定,C++中部分代码是需要在编译期间确定。

cpp 复制代码
#include <iostream>
#include <array> // 后面要学习的一个头文件

using namespace std;

// 表示是否可以在编译期间计算出返回值
constexpr int calc_len(int i)
{
    return i+5; // 随便写的计算规则
}

int main()
{
    // 5表示创建的arr对象的长度,必须在编译期间确定
    array<int,5> arr;

    // 编译期间可以计算出结果为6,正确
    array<int,calc_len(1)> arr2;

    int i = 1;
    // 编译期间无法计算出最后结果,报错
//    array<int,calc_len(i)> arr3; 错误

    return 0;
}
相关推荐
baivfhpwxf20233 分钟前
C# 5000 转16进制 字节(激光器串口通讯生成指定格式命令)
开发语言·c#
许嵩666 分钟前
IC脚本之perl
开发语言·perl
长亭外的少年16 分钟前
Kotlin 编译失败问题及解决方案:从守护进程到 Gradle 配置
android·开发语言·kotlin
直裾17 分钟前
Scala全文单词统计
开发语言·c#·scala
心仪悦悦17 分钟前
Scala中的集合复习(1)
开发语言·后端·scala
JIAY_WX19 分钟前
kotlin
开发语言·kotlin
代码小鑫1 小时前
A043-基于Spring Boot的秒杀系统设计与实现
java·开发语言·数据库·spring boot·后端·spring·毕业设计
Yang.991 小时前
基于Windows系统用C++做一个点名工具
c++·windows·sql·visual studio code·sqlite3