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

news/2024/11/17 2:17:05 标签: c++

友元的拓展语法

声明一个类为另外一个类的友元时,不再需要使用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;//err
    return 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.niftyadmin.cn/n/5754806.html

相关文章

生成式GPT商品推荐:精准满足用户需求

生成式GPT商品推荐&#xff1a;精准满足用户需求 随着人工智能&#xff08;AI&#xff09;技术的飞速发展&#xff0c;电商平台正在逐步迎来一场前所未有的变革。尤其是生成式GPT&#xff08;Generative Pre-trained Transformer&#xff09;技术的应用&#xff0c;正在重新定…

坚持燃油新能源双赛道发力,MG ES5MG7 2025款亮相广州车展

11月15日&#xff0c;第22届广州车展正式启幕&#xff0c;上汽MG名爵携“B级车王炸”MG7 2025款、全球高标准纯电后驱SUV MG ES5、“A级轿跑天花板”新一代MG5等明星阵容重磅登场&#xff0c;并通过一系列技术创新成果及精彩活动展示&#xff0c;尽显百年品牌独特魅力与强大实力…

tensorflow案例6--基于VGG16的猫狗识别(准确率99.8%+),以及tqdm、train_on_batch的简介

&#x1f368; 本文为&#x1f517;365天深度学习训练营 中的学习记录博客&#x1f356; 原作者&#xff1a;K同学啊 前言 本次还是学习API和如何搭建神经网络为主&#xff0c;这一次用VGG16去对猫狗分类&#xff0c;效果还是很好的&#xff0c;达到了99.8% 文章目录 1、tqdm…

kubesphere环境-本地Harbor仓库+k8s集群(单master 多master)+Prometheus监控平台部署

前言&#xff1a;半月前在公司生产环境上离线部署了k8s集群Victoria Metrics(二开版)自研版夜莺 监控平台的搭建&#xff0c;下面我租用3台华为云服务器演示部署kubesphere环境-本地Harbor仓库k8s集群&#xff08;单master节点 & 单master节点&#xff09;Prometheus监控部…

html + css 自适应首页布局案例

文章目录 前言一、组成二、代码1. css 样式2. body 内容3.全部整体 三、效果 前言 一个自适应的html布局 一、组成 整体居中&#xff0c;宽度1200px&#xff0c;小屏幕宽度100% 二、代码 1. css 样式 代码如下&#xff08;示例&#xff09;&#xff1a; <style>* {…

【IEEE出版 | 中国石油大学(华东)主办】第六届信息与计算机前沿术国际学术会议(ICFTIC 2024,12月13-15日)

第六届信息与计算机前沿术国际学术会议(ICFTIC 2024) 2024 6th International Conference on Frontier Technologies of Information and Computer 官方信息 会议官网&#xff1a;WWW.ICFTIC.ORG 2024 6th International Conference on Frontier Technologies of Information…

网络编程套接字2

之前我们已经介绍了UDP套接字流程&#xff0c;接下来我们介绍TCP流套接字编程&#xff0c;TCP的一个核心特点&#xff0c;面向字节流&#xff0c;读写数据的基本单位就是字节。 1.API介绍 1.1ServerSocket:是创建TCP服务器Socket的API&#xff08;专门给服务器用&#xff09;…

五、函数封装及调用、参数及返回值、作用域、匿名函数、立即执行函数

1. 函数基本使用 <!DOCTYPE html> <html lang"en"><head><meta charset"UTF-8"><meta name"viewport" content"widthdevice-width, initial-scale1.0"><title>Document</title><style&…