第17 章 智能指针
17.1 智能指针的实现
智能指针是包含重载运算符的类,用法类似普通指针,优点是及时安全地销毁动态分配的数据,并实现明确的对象声明周期,使智能指针“智能”的是:复制构造函数、赋值运算符、析构函数,它们决定了智能指针对象被传递给函数、赋值、离开作用域时的行为。
把指针封装在类中,给指针添加拷贝构造、赋值运算、析构,确保指针安全
class human{
public:
int age;
human(int a = 0) :age(a){}
void print()
{
cout << "Hello human:" << age << endl;
}
};
template<typename T>
class smart_pointer
{
private:
T* ptr;
public:
smart_pointer(T* p) :ptr(p){} //构造
~smart_pointer(){ delete ptr; } //析构
smart_pointer(const smart_pointer& obj);//拷贝构造
smart_pointer& operator=(const smart_pointer& obj);//赋值运算符
T& operator*() const //解引用运算符,重载
{
return *ptr;
}
T* operator->() const //成员选择运算符,重载
{
return ptr;
}
};
smart_pointer<human> p(new human);//将smart_pointer数据成员ptr 指向human对象
p->print(); //成员选择->被重载,返回ptr,其指向human对象
p->age = 100;
(*p).print(); //解引用*被重载,返回*ptr
17.2 智能指针在复制和赋值时的问题
- 指针共享(多个指针指向同以对象)
1、浅复制:直接复制指针,多次释放存在,悬挂指针
2、引用计数:直接复制指针,使用引用计数,多次释放安全,如(shared_ptr)
3、深复制:复制一份指向的对象,影响效率
- 指针独享(一个对象只能有一个指针)
4、破坏性复制:复制和赋值可使用,复制后原指针破坏,如(auto_ptr)
5、禁止复制:复制和赋值私有不可调用,可用移动构造函数转移控制权,如(unique_ptr)
17.2 浅复制
多个指针指向同一对象,当多次析构时,发生错误!
template<typename T>
class smart_pointer
{
private:
T* ptr;
public:
smart_pointer(T* p) :ptr(p){} //构造
~smart_pointer(){ delete ptr;} //析构
T& operator*() const //解引用运算符,重载
{
return *ptr;
}
T* operator->() const //成员选择运算符,重载
{
return ptr;
}
};
smart_pointer<human> p(new human);//将smart_pointer数据成员ptr 指向human对象
smart_pointer<human> p1(p);
//当析构时,多次释放
17.3 引用计数 shared_ptr(weak_ptr)
1、引用计数是对浅复制与深复制的折中操作,使用引用计数的规则如下:
1、创建智能指针,初始化指针
2、拷贝构造函数,复制指针,引用计数+1
3、复制操作符,先使左操作数引用计数-1,如果-1后为0,则释放指针所指对象内存;然后右操作数引用计数+1
2、通过辅助类模拟实现shared_ptr:
template<typename T>class smart_ptr; //模板类作为友元时要先声明
template <typename T> class refptr //辅助类
{//成员全部私有
private:
T* p; //对象指针
int count; //计数
refptr(T* ptr) :p(ptr), count(1){} //构造函数,count初始化为1
~refptr(){ delete p; } //析构函数
friend class smart_ptr<T>; //定义智能指针为友元类,智能指针需要直接操作辅助类
};
template<typename T>class smart_ptr //智能指针类
{
private:
refptr<T>* ptr;
public:
smart_ptr(T* p) :ptr(new refptr<T>(p)){}; //构造函数
smart_ptr(const smart_ptr<T> &p) :ptr(p.ptr){ ++ptr->count; } //复制构造函数
smart_ptr& operator=(const smart_ptr<T> &p) //赋值运算符
{
++p.ptr->count; //首先将右操作数引用计数+1
if (--ptr->count == 0) //左操作数被赋值,因此左操作数的指针-1,当count为0是删除
delete ptr;
ptr = p.ptr;
return *this;
}
T& operator*()
{
return *(ptr->p);
}
T* operator->()
{
return ptr->p;
}
~smart_ptr() //析构函数
{
if (--ptr->count == 0) //count为0时,删除辅助类对象指针
delete ptr;
else
{
cout << "还有 " << ptr->count << "个指针指向基础对象" << endl;
}
}
};
int main()
{
int *p1 = new int(10);//基础类对象指针
{
smart_ptr<int>p2(p1); //count=1
cout << *p2 << endl;
{
smart_ptr<int>p3(p2); //count=2
cout << *p3 << endl;
{
smart_ptr<int>p4 = p3; //count=3
cout << *p4 << endl;
} //count=2
} //count=1
} //count=0
cout << *p1 << endl;
return 0;
}
3、weak_ptr
weak_ptr配合shared_ptr使用,weak_ptr只对shared_ptr进行引用,不对其进行引用计数,shared_ptr失效时,weak_ptr也失效,不能直接通过weak_ptr来进行访问资源,访问资源时,使用lock()生成一个shared_ptr
weak_ptr可以用于解决循环引用问题
1、weak_ptr基本用法:
weak_ptr<T> w; //创建空weak_ptr
w = p; //p可以是shared_ptr或weak_ptr
w.reset(); //将w置空
w.use_count(); //返回shared_ptr的计数
w.expired(); //若w.use_count()为0,返回true,否则false
w.lock(); //若expired为true,返回空shared_ptr,否则返回非空shared_ptr
2、使用例子:
shared_ptr<int>p1(new int(10));
weak_ptr<int>p2(p1); //使用shared_ptr初始化weak_ptr
cout << p2.use_count() << endl; //使用use_count()获取shared_ptr的计数,此时为1
if (!p2.expired()) //
{
shared_ptr<int>p3 = p2.lock(); //使用lock()生成一个shared_ptr
cout << p2.use_count() << endl;//计数为2
*p3 = 100;
}
cout << p2.use_count() << endl;//计数为1
cout << *p1 << endl;
17.4 深复制
在智能指针复制时,将对象复制一份
class human{ //类
public:
int age;
human(int a = 0) :age(a){}
void print()
{
cout << "Hello human:" << age << endl;
}
};
template<typename T>
class smart_pointer
{
private:
T* ptr;
public:
smart_pointer(T* p) :ptr(p){} //构造
~smart_pointer(){ delete ptr;} //析构
smart_pointer(const smart_pointer& obj)//拷贝构造
{
ptr = new T; //重新new一个对象
ptr->age = obj.ptr->age;//copy值
}
smart_pointer& operator=(const smart_pointer& obj)//赋值运算符
{
if (ptr != obj.ptr)
{
ptr = new T; //重新new一个对象
ptr->age = obj.ptr->age;//copy值
}
return (*this);
}
T& operator*() const //解引用运算符,重载
{
return *ptr;
}
T* operator->() const //成员选择运算符,重载
{
return ptr;
}
};
smart_pointer<human> p(new human);
smart_pointer<human> p1(p); //复制
p1 = p; //赋值运算
17.5 破坏性复制 auto_ptr
智能指针在被复制时,将对象的所有权转交给目标指针,并重置原来的指针,确保任何时刻只有一个活动指针指向对象,适合从函数返回指针或需要破坏性的情况
//基于破坏性的智能指针实现:
template <typename T>
class destruct{
private:
T* ptr;
public:
destruct(T* p) :ptr(p){}//构造
~destruct(){ delete ptr; }//析构
destruct(destruct& obj)
{
ptr = obj.ptr; //传递指针
obj.ptr = 0; //破坏原指针
}
destruct& operator=(destruct& obj)
{
if (ptr != obj.ptr)
{
delete ptr;
}
ptr = obj.ptr; //传递指针
obj.ptr = 0; //破坏原指针
}
};
destruct<int>num(new int);
destruct<int>copy = num; //原指针将失效
17.6 禁止复制 unique_ptr
unique_ptr的拷贝构造函数与赋值运算符是私有的,因此不能按值传递,只能按引用传递,C++11引入的delete关键字:强制默认拷贝构造和赋值重载无法被生成。
1、unique_ptr基本操作:
unique_ptr<int> num1; //创建空智能指针
unique_ptr<int> num2(new int(1));//创建时指定
num1.reset(new int(10)); //reset()重新指定
int *p = num1.release(); //release()释放所有权
cout << *p << endl;
num2.reset(num1.release()); //转移所有权
cout << *num2 << endl;
num2 = move(num1); //所有权转移
cout << *num2 << endl;
num2.reset(); //清空智能指针,等价num2 = nullptr
num2 = nullptr;
2、unique_ptr禁止复制和赋值操作:
#include<memory>
class human{
public:
void print()
{
cout << "human" << endl;
}
};
void func(const unique_ptr<human>& p)
{
p->print();
}
unique_ptr<human> num1(new human);
func(num1); //可以使用引用参数形式
unique_ptr<human> num2(new human);
num2 = num1; //无法使用赋值运算符
3、如果unique_ptr是个临时右值,编译器允许拷贝:
unique_ptr<int> func(int num)
{
unique_ptr<int> temp(new int(num));//创建临时unique_ptr
return temp;
}
unique_ptr<int> n;
n = func(10); //func返回一个临时的unique_ptr
4、unique_ptr扩展auto_ptr不能完成的功能:
//1、unique_ptr可放在容器中
vector <unique_ptr<string>> num{ new string("Hello"), new string("World") };
vector <unique_ptr<string>> num1;
//2、管理动态数组,重载版本:unique_ptr<X[]>
unique_ptr<int[]> num2(new int[3]{11, 22, 33});
num2[0] = 111;
//3、自定义资源删除操作(delete)
第18 章 使用流进行输入输出
1、常见流类:
cout //标准输出流
cin //标准输入流
cerr //用于显示错误的标准输出流
fstream //用于操作文件的输入输出流,继承了ofstream和ifstream
ofstream //用于操作文件的输出流,
ifstream //用于操作文件的输入流,
stringstream//用于操作字符串的输入输出流,在字符串和其它类型中进行转换
2、流控制符:
setbase //设置基数,与使用dec、oct、hex等价
dec //十进制
oct //八进制
hex //十六进制
setiosflag //通过类型为std::ios_base::fmtflags的掩码输入参数设置标志
resetiosflags //将setiosflag指定的参数重置为默认参数
setprecision //设置小数精度
fixed //以定点表示法显示数据
scientific //以科学计数法显示数据
setw //设置字段宽度
setfill //设置填充字符
18.1 cout
std::out用于将数据写入标准输出流
1、修改显示格式:
int input = 0;
cin >>input;//setiosflags()设置格式,参数1:八进制,参数2:显示基数,参数3:大写
cout << setiosflags(ios_base::hex | ios_base::showbase | ios_base::uppercase);
cout << oct << input << endl; //oct设置八进制
cout << hex << input << endl; //hex设置十六进制,使用setiosflags设置的格式
cout << resetiosflags(ios_base::hex | ios_base::showbase | ios_base::uppercase);
cout << input << endl;//resetiosflags()重置setiosflags()设置的格式
2、以定点表示法和科学计数法显示数据:
const double Pi = (double)22.0 / 7;
cout << Pi << endl; //正常输出double
cout << setprecision(10) << Pi << endl; //设置小数精度
cout << fixed << Pi << endl; //设置定点表示法输出
cout << scientific << Pi << endl; //设置科学计数法输出
3、字段宽度和填充
cout << setw(25); //设置字段宽度
cout << Pi << endl;
cout << setw(25) << setfill('*'); //设置填充字符
cout << Pi << endl;
18.2 cin
使用cin将标准输入读取到给定的变量中
1、基本输入:
int num1;
cin >> num1; //输入
cout << num1 << endl;
double num2;
cin >> num2; //输入
cout << setprecision(10)<<num2<<endl;
char s1, s2, s3;
cin >> s1 >> s2 >> s3; //输入
cout << s1 << s2 << s3 << endl;
2、字符串读入:
char str[10];
cin >> str; //输入字符串,可越界
cin.get(str, 10); //get()限制读入的数量
cout << str << endl;
string name;
cin >> name; //读入空格停止插入
cout << name << endl; //
getline(cin, name); //可读入空格
cout << name << endl;
18.3 fstream
1、打开open与关闭close
文件打开模式:
ios_base::app; //追加
ios_base::ate; //切换到文件尾
ios_base::trunc; //入锅文件存在则删除再创建
ios_base::binary; //创建二进制文件,(默认文本文件)
ios_base::in; //只读
ios_base::out; //只写
fstream file; //文件可读可写
//ofstream file1; //文件只写
//ifstream file2; //文件只读
file.open("1.txt", ios_base::in | ios_base::out |ios_base::trunc);//打开文件
if (file.is_open()) //判断文件是否打开成功
{
file.close(); //关闭文件
}
2、文件读写
file << "Hello World"<<endl; //写入文件:插入运算符<<进行文件写入
string str;
char s[100];
char c;
file >> str; //读方式1:读入空格时会终止
getline(file, str); //读方式2:读入一行
file.getline(s, 100); //读方式3:读入一行
while ((c = file.get()) != EOF) //读方式4:循环读取字符
3、文件指针
istream的seekg("seek get")和ostream的seekp("seek put")
ios::beg;文件头,默认
ios::cur;文件当前位置
ios::end;文件尾
file.seekp(0, ios::beg); //将文件指针移动到文件头
4、二进制文件读写
打开方式:ios_base::binary
二进制读:read
二进制写:write
struct human{
string name = "wang";
int age = 20;
double score = 99.99;
};
human p; //构造函数打开,二进制格式
fstream file("1.dat", ios_base::in | ios_base::out | ios_base::binary);
if (file.is_open())
{
file.write(reinterpret_cast<char*>(&p),sizeof(p)); //强制转换类型
human h;
file.read((char*)&h, sizeof(h)); //强制转换类型
cout << h.name << endl;
cout << h.age << endl;
cout << h.score << endl;
file.close();
}
18.4 stringstream
stringstream,可以用分割字符串或类型转换,例如:将字符串值100转为整数值100,或者将整数100转为字符串
1、stringstream类型转换:
#include<sstream>
int num1 = 100,num2=0;
string str;
stringstream int_to_str, str_to_int;
int_to_str << num1; //int放入stringstream对象
int_to_str >> str; //转给string
cout << str << endl;
str_to_int << str; //str放入stringstream对象
str_to_int >> num2; //转给int
cout << num2 << endl;
第19 章 异常处理
19.1 使用try和catch捕获异常
1、使用catch块对try块可能引发的异常进行处理:
#include<iostream>
using namespace std;
int main()
{
try //try块
{
int n;
cin >> n;
int* p = new int[n];//输入-1,分配内存失败,异常类型为std::bad_alloc
delete[] p;
}
catch (...) //catch块,发生异常catch将捕获
{
cout << "error!" << endl;
}
return 0;
}
2、捕获特定类型异常:
int main()
{
try
{
int n;
cin >> n;
int* p = new int[n];
delete[] p;
}
catch(bad_alloc& exp) //捕获bad_alloc异常
{
cout<<exp.what()<<endl;
}
catch (...)
{
cout << "error!" << endl;
}
return 0;
}
3、使用throw引发特定类型的异常:
double divide(double a,double b)// 功能:a/b
{
if(b == 0)
throw "除数不能为0!"; //字符串
return a/b;
}
int main()
{
try
{
cout<<divide(10,0);
}
catch(const char* exp) //捕获类型为char*的异常
{
cout<<exp<<endl;
}
return 0;
}
19.2 异常处理的工作原理
1、异常逻辑工作原理
try引发异常后,先在函数内寻找能处理该异常的catch,没有则将在调用函数中进行寻找,异常逻辑沿调用栈向上逐个寻找,直到找到可处理异常的catch,在退栈的每一步中,都将销毁当前函数的局部变量。不要再析构函数中引发异常!
#include<iostream>
#include<string>
using namespace std;
struct structA
{
string name;
structA(const string str) :name(str){ cout << name << ": structA 构造" << endl; }
~structA(){ cout << name << ": structA 析构" << endl; }
};
struct structB
{
string name;
structB(const string str) :name(str){ cout << name << ": structB 构造" << endl; }
~structB(){ cout << name << ": structB 析构" << endl; }
};
void func_B()
{
cout << "---- At func_B ----" << endl;
structA objA("func_B");
structB objB("func_B");
throw "Throwing!";
cout << "---- End func_B ----" << endl;
}
void func_A()
{
structA objA("func_A");
try
{
cout << "---- At func_A ----" << endl;
structA objA("func_A");
structB objB("func_A");
func_B();
cout << "---- End func_A ----" << endl;
}
catch (const char* exp)
{
cout << "func_A catch:" << exp << endl;
//throw; 将异常传播给func_A的调用者,main也会收到该异常
}
}
int main()
{
try
{
func_A();
}
catch (const char* exp)
{
cout << "main catch:" << exp << endl;
}
system("pause");
return 0;
}
19.3 从std::exception派生出自定义异常类
在捕获std::bad_alloc时,实际上捕获的是new引发的std::bad_alloc对象,bad_alloc继承自exception类,std::exception类是异常基类,定义了虚函数what(),exception类是很多异常类型的基类,因此可以使用catch(const exception&)捕获所有将exception作为基类的异常。
#include<exception>
try
{
}
catch (const exception& exp)
{
cout << exp.what() << endl;
}
派生出自定义异常类:
class myexception :public exception
{
private:
string reason;
public:
myexception(const char* why) :reason(why){}//构造函数
virtual const char* what()const throw() //实现虚函数what() 最后的throw()表示这个函数不会引发异常
{ //throw(int)表示该函数可能引发类型为int的异常
return reason.c_str();
}
};
double divide(double a, double b)
{
if (b == 0)//除数为0
throw myexception("myexception: divide by 0"); //此时实例化一个对象,并引发它
return a / b;
}
int main()
{
try
{
cout << divide(10, 0);
}
catch (exception& exp)
{
cout << exp.what() << endl;
}
return 0;
}
第20 章 C++20
20.1 概念
1、使用模板进行泛型编程时,模板类可支持不同类型的属性,调用模板函数时可提供不同类型的参数,具体取决于实例化。
template <typename T>
double divide(T a,T b)
{
return a/b;
}
divide(22.0,7.0); //正常情况
divide("abc","123"); //编译错误!
2、编译器报告错误,改进后编译器拒绝编译:
template <floatint_point T> //floatint_point是一个概念,约束T的类型为浮点型
double divide(T a,T b)
{
return a/b;
}
3、标准库提供的一些重要概念:
概念 | 描述 |
integral | 验证整数 |
signed_integral | 验证有符号整数 |
unsigned_integral | 验证无符号整数 |
floatint_point | 验证浮点数 |
same_as | 验证两种类型相同 |
derived_from | 验证一种类型是从另一种类型派生的 |
convertible_to | 验证一种类型可转换为另一种类型 |
4、使用关键字requires自定义概念
#include<iostream>
#include<concepts>
using namespace std;
template <typename T>
concept myconcept = floating_point<T> || integral<T>; //自定义概念myconcept,整形或浮点型
template <typename T> //integral概念 限制整形
requires integral<T> //对T的类型进行检查,integral限制整型
double divide1(T a,T b)
//requires integral<T> //可放在这里
{
return a/b;
}
template <typename T1,typename T2> //两个参数类型为整形或浮点型,两者类型可以不同
requires myconcept<T1> && myconcept<T2>
double divide2(T1 a,T2 b)
{
return a/b;
}
template <typename T1,typename T2> //两个参数类型相同
requires same_as<T1,T2>
double divide3(T1 a,T2 b)
{
return a/b;
}
int main()
{
cout<<divide1(22,7)<<endl; //OK
cout<<divide1(22.0,7)<<endl; //error,限定整型
cout<<divide2(22.0,7)<<endl; //OK
cout<<divide2(22.0,7.0)<<endl; //OK
cout<<divide2(22.0,'7')<<endl; //OK
cout<<divide2("22.0",'7')<<endl;//error,限定整型,浮点型
cout<<divide3(22,7)<<endl; //OK
cout<<divide3(22.0,7.0)<<endl; //OK
cout<<divide3(22.0,7)<<endl; //error,类型不相同
return 0;
}
5、将概念用于类和对象
template <typename T>
concept myconcept = floating_point<T> || integral<T>; //自定义概念 myconcept,整形或浮点型
template<myconcept T1,myconcept T2> //使用自定义概念myconcept进行类型限制
class human
{
public:
T1 age;
T2 score;
human(T1 num1, T2 num2):age(num1),score(num2){}
};
int main()
{
human<int,double>p1(21,3.14);
human<double,float>p2(32,3.14f);
human<string,double>p3("wang",3.14);//error
return 0;
}
6、使用概念derived_from验证继承关系
class human{};
class student:public human{};
class teacher:public human{};
class monkey:private human{};
class dog{};
template<derived_from<human> T>
void func(T& input)
{
cout<<"HELLO WORLD"<<endl;
}
int main()
{
student s;
func(s); //OK
teacher t;
func(t);//OK
dog d;
func(d);//error 非继承human
int n=10;
func(n); //其它类型不行
monkey m;
func(m);//error 私有继承human
return 0;
}
20.2 范围库、视图和适配器
1、范围
范围是对集合的抽象,支持begin()和end()方法的集合都是范围,例如:vector、list、set、map等容器属于范围,stack、forward_list等不满足 begin()和end()方法的不属于范围 。
2、视图和适配器
视图是复制、移动和赋值时间固定的范围,是一种特殊的范围,所有视图都是范围,但范围不一定都是视图。
适配器是算法,使用适配器 创建集合 的各种视图。
STL提供的常用适配器:
适配器 | 描述 |
std::views::reverse | 反序查看集合中的元素 |
std::views::all | 查看集合中所有元素 |
std::views::filter(p) | 只查看满足谓词p的元素 |
std::views::drop(n) | 查看集合中元素,忽略前n个的元素 |
std::views::take(n) | 查看前n个元素 |
std::views::transform(f) | 查看函数f作用于范围后的各个元素的结果 |
3、按照相反顺序查看集合的视图
vector<int> num{1,5,202,-99,42,50};
auto view_reverse = num | views::reverse; //使用适配器reverse创建一个名为view_reverse的视图
for(int n:num) //基于范围遍历
cout<<n<<endl;
for(int n:view_reverse) //视图view_reverse属于范围
cout<<n<<endl;
3、使用适配器生成集合的视图
template<ranges::view T> //使用概念ranges::view限制模板类型
void display(T& view)
{
for(auto element:view)
cout<<element<<endl;
cout<<endl;
}
int main()
{
vector<int>num{1,5,202,-99,42,50};
auto view_all = num | views::all; //1、适配器:views::all
display(view_all);
auto view_filter = num | views::filter([](auto num){return ((num%2)==0);});
display(view_filter); //2、适配器:views::filter(只查看满足谓词的元素 )
auto view_drop = num | views::drop(2);//3、适配器:views::drop
display(view_drop);
auto view_take = num | views::take(3);//4、适配器:views::take
display(view_take);
auto view_reverse = num | views::reverse;//5、适配器:views::reverse
display(view_reverse);
auto view_transform = num | views::transform([](auto num){return (num%2);});
display(view_transform);//6、适配器:views::transform(返回函数对每个元素作用的结果)
4、使用管道符号 ( | ) 合并多个适配器
template<ranges::view T> //使用概念ranges::view限制模板类型
void display(T& view)
{
for(auto element:view)
cout<<element<<" ";
cout<<endl;
}
int main()
{
vector<int>num{1,5,202,-99,42,50};
auto lambda_even = [](auto num){return ((num%2)==0);};//lambda
auto view1 = num | views::reverse | views::filter(lambda_even);
display(view1);
auto view2 = num | views::reverse | views::filter(lambda_even) | views::take(2);
display(view2);
return 0;
}
20.3 多线程
不同操作系统的系统调用接口不同,线程API也不同,C++多线程封装后,可在不同平台使用统一接口,实现可移植性,C++20引入协程。
#include<thread>
#include<iostream>
using namespace std;
void thread_func(stop_token stop)
{
while(true)
{
cout<<"Worker thread: hello"<<endl;
this_thread::sleep_for(1s); //等1s
if(stop.stop_requested()) //接收停止信号
{
cout<<"Worker thread: ending"<<endl;
break;
}
}
}
int main()
{
//jthread类
jthread myThread(thread_func);//thread_func作为构造函数的参数
this_thread::sleep_for(5s); // this_thread类,成员函数sleep_for()使当前线程挂起
myThread.request_stop(); //让线程停止
cout<<"Main thread: Waiting"<<endl;
myThread.join(); //等待线程停止
cout<<"Main thread: yes"<<endl;
return 0;
}
20.4 模块
#include<header>头文件问题:
1、重复包含多个文件
2、展开后代码量增大,包含与当前编译程序无关的代码,增加编译器负担
3、减慢编译器速度,可能导致重复定义错误
4、包含的顺序很重要
import std.core; //模块core包括iostream的函数,取代#include<iostream>
int main()
{
std::cout << "Hello World!" << std::endl;
return 0;
}
//1、模块声明:(文件mymodule.ixx):
export module mymodule; //声明模块名mymodule,export表示外部可见
export int add(int a, int b); //模块中的函数add(),export表示外部可见
//2、模块实现:(文件mymodule.cpp)
module mymodule;
int add(int a, int b)
{
return a + b;
}
//3、模块使用:(文件main.cpp)
import mymodule;
int main()
{
int sum = add(10, 10); //使用模块中的函数add()
return 0;
}