C++常用的特性-->day05

embedded/2024/11/17 23:02:11/

友元的拓展语法

声明一个类为另外一个类的友元时,不再需要使用class关键字,并且还可以使用类的别名(使用 typedef 或者 using 定义)。

#include <iostream>
using namespace std;// 类声明
class Tom;
// 定义别名
using Honey = Tom;// 定义两个测试类
class Jack
{// 声明友元// friend class Tom;    // C++98 标准语法friend Tom;             // C++11 标准语法 string name = "jack";   // 默认私有void print()            // 默认私有{cout << "my name is " << name << endl;}
};class Lucy
{
protected:// 声明友元// friend class Tom;    // C++98 标准语法friend Honey;           // C++11 标准语法 string name = "lucy";void print(){cout << "my name is " << name << endl;}
};class Tom
{
public:void print(){// 通过类成员对象访问其私有成员cout << "invoke Jack private member: " << jObj.name << endl;cout << "invoke Jack private function: " << endl;jObj.print();cout << "invoke Lucy private member: " << lObj.name << endl;cout << "invoke Lucy private function: " << endl;lObj.print();}
private:string name = "tom";Jack jObj;Lucy lObj;
};int main()
{Tom t;t.print();return 0;
}

在这里插入图片描述

类模板的友元应用

在c++98时不可以为类模板声明友元,c++11新特性是可以声明为友元的

基本用法

class Tom;template<typename T>
class Person
{friend T;
};int main()
{Person<Tom> p;// >>>>>>>>>> Tom类是Person类的友元Person<int> pp;// >>>>>>>>>>> 对于int类型的模板参数,友元声明被忽略(第6行)return 0;
}

复杂案例

#include<iostream>
using namespace std;
template<typename T>
class Rectangle
{
public:friend T;Rectangle(int w, int h) : width(w), height(h) {}
private:int width;int height;
};template<typename T>
class Circle
{
public:friend T;Circle(int r) : radius(r) {}
private:int radius;
};// 校验类
class Verify
{
public:void verifyRectangle(int w, int h, Rectangle<Verify>& r){if (r.width >= w && r.height >= h){cout << "矩形的宽度和高度满足条件!" << endl;}else{cout << "矩形的宽度和高度不满足条件!" << endl;}}void verifyCircle(int r, Circle<Verify>& c){if (r >= c.radius){cout << "圆形的半径满足条件!" << endl;}else{cout << "圆形的半径不满足条件!" << endl;}}
};int main()
{Verify v;Circle<Verify> circle(30);Rectangle<Verify> rect(90, 100);v.verifyCircle(60, circle);v.verifyRectangle(100, 100, rect);return 0;
}

在这里插入图片描述

强类型枚举

枚举的缺陷

// 匿名枚举
enum {Red, Green, Blue};
// 有名枚举
enum Colors{Red, Green, Blue};

如果这个时候在main函数下执行:

cout<<"red:"<<red<<endl;//err 属于重定义

错误的原因:在这两个枚举中Red是全局可见的,所有编译器就会提示其重定义了。

强类型枚举语法

针对枚举的缺陷,C++11标准引入了一种新的枚举类型,即枚举类,又称强类型枚举(strong-typed enum)。
声明强类型枚举非常简单,只需要在 enum 后加上关键字 class

强类型枚举特性

  • 强作用域,强类型枚举成员的名称不会被输出到其父作用域空间。
  • 强类型枚举只能是有名枚举,如果是匿名枚举会导致枚举值无法使用(因为没有作用域名称)。
    转换限制,强类型枚举成员的值不可以与整型隐式地相互转换
  • 可以指定底层类型。强类型枚举默认的底层类型为 int,但也可以显式地指定底层类型
    具体方法为在枚举名称后面加上∶type,其中 type 可以是除 wchar_t 以外的任何整型。比如:
#include<iostream>
using namespace std;enum class Color:char{ Red, Green, Blue };
enum struct Color1 { Red, Green, Blue };int main()
{cout << "red:" << (int)Color::Red << endl;int m = (int)Color::Green;cout << "green:" << (int)Color::Green << endl;cout << "sizeof Color:char" << sizeof(Color) << endl;cout << "sizeof Color1:" << sizeof(Color1) << endl;return 0;
}

在这里插入图片描述

对原有枚举的拓展

原有枚举类型的底层类型在默认情况下,仍然由编译器来具体指定实现。但也可以跟强类型枚举类一样,显式地由程序员来指定。其指定的方式跟强类型枚举一样,都是枚举名称后面加上∶type,其中type 可以是除 wchar_t 以外的任何整型

#include<iostream>
using namespace std;enum TestColor:char { Red='a', Green, Blue };//>>>>>>普通枚举是可以直接访问的enum class Color:char{ Red, Green, Blue };
enum struct Color1 { Red, Green, Blue };int main()
{cout << "TestColor Red:" << Red << endl<< "TestColor Red:" << TestColor::Red << endl;cout << "sizeof TestColor:" << sizeof(TestColor) << endl;cout << "Red:" << (int)Color::Red << endl;int m = (int)Color::Green;cout << "green:" << (int)Color::Green << endl;cout << "sizeof Color:char" << sizeof(Color) << endl;cout << "sizeof Color1:" << sizeof(Color1) << endl;return 0;
}

在这里插入图片描述

非受限联合体

静态类型的数据/成员在非受限联合体的使用

在c++11里面不受限的是:静态类型的成员、POD类型
对于引用还是受限制的

#include<iostream>
using namespace std;union Test
{int age;long id;// int& tmp = age; // error >>>>>>>>> 非受限联合体中不允许出现引用类型static char c;static int print(){cout << "c value: " << c << endl;return 0;}
};
char Test::c;
// char Test::c = 'a';int main()
{Test t;Test t1;t.c = 'b';t1.c = 'c';t1.age = 666;cout << "t.c: " << t.c << endl;cout << "t1.c: " << t1.c << endl;//在联合体中,所有成员共享相同的内存空间。所以,当你给某个成员赋值时,其他成员的值也会被改变// //在非受限联合体中静态成员变量和非静态成员变量使用的不是同一块内存cout << "t1.age: " << t1.age << endl;cout << "t1.id: " << t1.id << endl;t.print();Test::print();return 0;
}

在这里插入图片描述

POD类型在非受限联合体的使用

union Student 中包含了一个 string 类型成员,而 std::string 是一个复杂的类类型,具有构造函数、析构函数和其他成员函数。由于 string 类型的存在,Student 联合体不能被视为 POD 类型。

如果原本类中的是POD类型,如果这个时候添加了一段自定义的构造函数那么此时的类就不是POD类型

union Student
{int id;string name;
};int main()
{Student s;//errreturn 0;
}

由于非POD类型在非受限联合体的使用,这个联合体的构造函数就会被删除。

解决方案:手动地去指定一块内存空间

即–>使用placement new

placement new

  • 使用new申请内存空间:Base* ptr = new Base;
  • 使用定位放置new申请内存空间:
    ClassName* ptr = new (定位的内存地址)ClassName;
简单案例
#include <iostream>
using namespace std;class Base
{
public:Base() {}~Base() {}void print(){cout << "number value: " << number << endl;}
private:int number;
};int main()
{int n = 100;Base* b = new (&n)Base;// >>>>> 使用placement new指定栈内存(n的)为存储空间b->print();return 0;
}

在这里插入图片描述

  • 使用定位放置new操作,既可以在栈(stack)上生成对象,也可以在堆(heap)上生成对象,这取决于定位时指定的内存地址是在堆还是在栈上。
  • 从表面上看,定位放置new操作是申请空间,其本质是利用已经申请好的空间,真正的申请空间的工作是在此之前完成的。
  • 使用定位放置new 创建对象时会自动调用对应类的构造函数,但是由于对象的空间不会自动释放,如果需要释放堆内存必须显示调用类的析构函数。
  • 使用定位放置new操作,我们可以反复动态申请到同一块堆内存,这样可以避免内存的重复创建销毁,从而提高程序的执行效率(比如网络通信中数据的接收和发送)
复杂案例
#include<iostream>
using namespace std;
class Base
{
public:void setText(string str){notes = str;}void print(){cout << "Base notes: " << notes << endl;}
private:string notes;
};union Student
{Student(){new (&name)string;//选取占内存最大的}~Student() {}int id;Base tmp;string name;
};int main()
{Student s;s.name = "蒙奇·D·路飞";cout << "Student name: " << s.name << endl;s.tmp.setText("我是要成为海贼王的男人!");s.tmp.print();cout << "Student name: " << s.name << endl;//>>>>>>共用同一块内存return 0;
}

在这里插入图片描述

匿名的非受限联合体

在这里插入图片描述

#include<iostream>
using namespace std;
/*木叶村要进行第99次人口普查,人员的登记方式如下:- 学生只需要登记所在学校的编号- 本村学生以外的人员需要登记其身份证号码- 本村外来人员需要登记户口所在地+联系方式
*/
// 外来人口信息
struct Foreigner
{Foreigner(string s, string ph) : addr(s), phone(ph) {}string addr;string phone;
};// 人口信息
class Person
{
public://枚举出人员身份enum class Category : char { Student, Local, Foreign };Person(int num) : number(num), type(Category::Student) {}Person(string id) : idNum(id), type(Category::Local) {}Person(string addr, string phone) : foreign(addr, phone), type(Category::Foreign) {}~Person() {}void print(){cout << "Person category: " << (int)type << endl;switch (type){case Category::Student:cout << "Student school number: " << number << endl;break;case Category::Local:cout << "Local people ID number: " << idNum << endl;break;case Category::Foreign:cout << "Foreigner address: " << foreign.addr<< ", phone: " << foreign.phone << endl;break;default:break;}}private:Category type;union{int number;string idNum;Foreigner foreign;};
};int main()
{Person p1(9527);Person p2("1101122022X");Person p3("砂隐村村北", "1301810001");p1.print();p2.print();p3.print();return 0;
}

在这里插入图片描述


http://www.ppmy.cn/embedded/138047.html

相关文章

TCP编程API

这里写自定义目录标题 主要的 TCP 编程 API 函数1.1 socket()1.2 bind()1.3 listen()1.4 accept()1.5 connect()1.6 send()1.7 recv()1.8 close() 主要的 TCP 编程 API 函数 1.1 socket() 创建一个新的套接字。 int socket(int domain, int type, int protocol);domain&…

Leetcode 相同的树

这段代码的算法思想是通过递归来判断两棵二叉树是否相同。以下是详细的解释&#xff1a; 递归终止条件&#xff1a;如果两棵树的当前节点 p 和 q 都是 null&#xff0c;则说明在这个节点上它们是相同的&#xff0c;所以返回 true。这是因为两棵树的对应节点都不存在&#xff0c…

10月回顾 | Apache SeaTunnel社区动态与进展一览

各位热爱 Apache SeaTunnel 的小伙伴们&#xff0c;社区10月份月报来啦&#xff0c;请查收&#xff01; 这里将记录Apache SeaTunne社区每月动态和进展&#xff0c;欢迎关注。 月度Merge之星 感谢以下小伙伴上个月为 Apache SeaTunnel 所做的精彩贡献&#xff08;排名不分先…

GPT-5 要来了:抢先了解其创新突破

Microsoft 的工程师计划于 2024 年 11 月在 Azure 上部署 Orion (GPT-5)。虽然这一版本不会向公众开放&#xff0c;但其上线被视为人工智能领域的一个重要里程碑&#xff0c;并将产生深远的影响。 文章目录 GPT-5 真的要来了GPT-4 的局限性GPT-5 的创新突破与遗留挑战GPT-5 预期…

Spark RDD 的 compute 方法

角度一 Spark RDD 的 compute 方法 1. 什么是 compute&#xff1f; compute 是 Spark RDD 中的核心方法之一。 它定义了如何从特定的分区中获取数据&#xff0c;并返回一个 迭代器&#xff0c;供上层操作使用。每个 RDD 的计算逻辑由 compute 方法决定&#xff0c;不同类型的…

外星人入侵

学习于Python编程从入门到实践&#xff08;Eric Matthes 著&#xff09; 整体目录&#xff1a;外星人入侵文件夹是打包后的不必在意 图片和音效都是网上下载的 音效下载网站&#xff1a;Free 游戏爆击中 Sound Effects Download - Pixabay 运行效果&#xff1a;可以上下左右移…

人群计数制作私有数据集教程-----自用

一、人群计数的数据集包括两部分&#xff1a;图像部分和标签部分 1.公开数据集格式 标签部分主要包括每个人头的坐标点&#xff1a;&#xff08;x, y&#xff09;&#xff1b; 常见的标签格式例如&#xff1a;ShanghaiTech数据集中的格式&#xff0c;用mat文件存储每个人头的坐…

气膜球幕展览馆:开启元宇宙时代的沉浸式科技体验—轻空间

在数字化浪潮的推动下&#xff0c;现代展览馆逐步迈向全新的发展方向。我们带来了极具创新性的气膜球幕展览馆&#xff0c;以沉浸式体验为核心&#xff0c;打造出逼真、震撼的视觉空间。这一球幕展览馆不仅拥有高度还原的真实感&#xff0c;更能够通过前沿科技实现元宇宙场景的…