首页 > 编程语言 >C++友元

C++友元

时间:2023-02-19 15:32:42浏览次数:38  
标签:友元 const cout int void C++ cast MM


title: C++友元 date: 2022-05-20 18:37:54 tags: C++ category: cpp


参考书籍:

C++ Primer
Essential C++

编译器:

gcc / g++

C++友元

C++友元是用friend关键修饰的函数或者类,友元用来打破类封装(忽视权限限定)

  • 友元并不是说直接访问数据成员,友元只是提供一个场所赋予对象具有打破权限限定
  • 友元函数
  • 友元类
  • 友元函数和友元类不属于当前类,实现函数或者类不需要类名限定

友元函数

  • 普通函数成为类的友元函数
#include <iostream>
#include <string>
using namespace std;
class MM {
public:
MM(string name, int age, int num) : name(name), age(age), num(num) {}
void print();
//友元函数
friend void visitedData();
friend void visited(MM mm);

protected:
int num;

private:
int age;
string name;
};
void MM::print() {
cout << name << "\t" << age << "\t" << num << endl;
}
//友元函数
void visitedData() {
// name = "ILoveyou"; 不是直接访问,赋予对象的具有这样权限
//创建对象的无视权限
MM mm("girl", 18, 1001);
cout << mm.name << "\t" << mm.age << "\t" << mm.num << endl;
MM* p = new MM("new", 28, 1002);
cout << p->name << "\t" << p->age << "\t" << p->num << endl;
}
void visited(MM mm) {
cout << mm.name << "\t" << mm.age << "\t" << mm.num << endl;
}
int main(int argc, char** argv) {
MM girl("girl", 19, 1002);
// girl.name="name"; //类外只能访问public
girl.print();
visitedData();
visited(girl);
return 0;
}

以另一个类的成员函数为友元函数

#include <iostream>
#include <string>
using namespace std;
//前向声明
class A;
class B {
public:
B(int b) : b(b) {}
void printA(A object);

private:
int b;
};

class A {
public:
A(int a) : a(a) {}
friend void B::printA(A object);

private:
int a;
};

void B::printA(A object) {
cout << object.a << endl;
}
int main(int argc, char** argv) {
B b(111);
A a(222);
b.printA(a);

return 0;
}
/*
A以B的成员函数为友元函数,
B又以A类的成员函数为友元,
如果存在这种需求,
代码设计有问题,
但是C++允许这种关系
*/

友元类

#include <iostream>
#include <string>
using namespace std;
class MM {
friend class Boy; //声明boy类是MM友元类
public:
MM(string name) : name(name) {}

private:
string name;
};

//友元类中,MM类的对象无视权限
class Boy {
public:
Boy() : mm("mm") { pObject = new MM("Object"); }
void print() {
cout << "访问私有属性:" << mm.name << endl;
cout << "访问私有属性:" << pObject->name << endl;
MM* pMM = new MM("new");
cout << "访问私有属性:" << pMM->name << endl;
}

private:
MM mm;
MM* pObject;
};

class A {
public:
friend class B;
void printA();

private:
string a_name = "A";
};

class B {
public:
friend class A;
void printB() {
A a;
cout << a.a_name << endl;
}

private:
string b_name = "B";
};

void A::printA() {
B b;
cout << b.b_name << endl;
}
int main(int argc, char** argv) {
Boy boy;
boy.print();
B b;
b.printB();
A a;
a.printA();
return 0;
}

顺便介绍一下C++的强制类型转换

#include <iostream>
using namespace std;
int main(int argc, char** argv) {
int num = 1.11;
cout << num << endl;
int cnum = (int)1.11;
cout << cnum << endl;
int cppnum = int(1.22); // C++强制类型转换
cout << cppnum << endl;
return 0;
}

static_cast类型转换

类似C语言的强制类型转换,按照C++的说法 比C语言的更为安全

  • 基本数据类型的强制转换
  • 空指针转换目标类型指针
  • 不能操作带const属性的类型
// static_cast<要转换的类型>(要转换目标)
//要转换的类型: 数据类型
//要转换目标 可以是表达式,或者常量,都可以
#include <iostream>
using namespace std;

void test_static_cast() {
// No.1 基本数据类型的强制转换
int num = static_cast<int>(1.111);
// No.2 空类型指针的转换
double* pD = new double(1.11);
void* pVoid = static_cast<void*>(pD);
// No.3 不能做const属性的类型的转换
//增加const属性
//不能去掉const属性
int number = 11;
const int cNum = static_cast<const int>(number);
const int ccNum = number;
const int data = 1;
int* pData = (int*)(&data); // C语言强制类型转换
// int* pcData = static_cast<int*>(&data); //错误
}
int main(int argc, char** argv) {
test_static_cast();
return 0;
}

const_cast类型转换

  • 去掉const属性(提供一个可以修改接口去操作const数据类型)
  • 加上const属性(用的少一点)
#include <iostream>
using namespace std;

class Str {
public:
// 1.去掉const属性
Str(const char* str) : str(const_cast<char*>(str)) {}
void print() {
cout << str << endl;
}

private:
char* str;
};
class Test {
public:
void print() {
cout << "普通函数" << endl;
}

private:
};
void printTest(const Test& object) {
Test& m_test = const_cast<Test&>(object);
m_test.print();
}

void test_const_cast() {
// 2.增加const属性
const int data = 1;
int* pData = const_cast<int*>(&data);
*pData = 1001; //不会作用到const变量,只是单纯提供一个接口
cout << "data:" << data << endl;
cout << "*pData:" << *pData << endl;
cout << &data << endl;
cout << pData << endl;
Str str("ILoveyou"); //错误,C++对于const要求更为严格
str.print();
char sstr[20] = "ILoveyoud";
Str str2(sstr);
str2.print();
// 3.引用类型
Test test;
test.print();
const Test& c_test = test;
// c_test.print(); //常属性的对象只能调用常成员函数
Test& m_test = const_cast<Test&>(c_test);
m_test.print();
}

int main(int argc, char** argv) {
test_const_cast();
return 0;
}

reinterpreat_cast类型转换

把指针转换为一个整数,又可以把整数转换为一个指针,指针的效果依然有效

#include <iostream>
using namespace std;
int Max(int a, int b) {
return a > b ? a : b;
}
//官方案例
unsigned short Hash(void* p) {
unsigned int val = reinterpret_cast<unsigned int>(p);
return (unsigned short)(val ^ (val >> 16));
}

void test_reinterpret_cast() {
int* p = reinterpret_cast<int*>(0); // p=nullptr;
//官方案例
int a[20];
for (int i = 0; i < 20; i++)
cout << Hash(a + i) << endl;

//允许将任何指针转换为任何其他指针类型。
//也允许将任何整数类型转换为任何指针类型以及反向转换
int* num = reinterpret_cast<int*>(Max); //把函数地址转换为int类型的数字
cout << *num << endl;
auto pMax = reinterpret_cast<int (*)(int, int)>(num);
cout << "max:" << pMax(1, 2) << endl;
}
int main(int argc, char** argv) {
test_reinterpret_cast();
return 0;
}

标签:友元,const,cout,int,void,C++,cast,MM
From: https://blog.51cto.com/u_15959862/6066733

相关文章

  • C++ 简单IocContainer
    IocContainer.h#pragmaonce#include<map>#include<string>#include<functional>#include<memory>#include<stdexcept>template<classT>classIocContainer{......
  • 基于clangd配置sublime text4为C++编辑器
    概述涉及以下插件的安装和配置PackageControlTerminusLSPLSP-clangdclang-formatLSP-pylspLSP-json配置sublime安装PackageControl以进行包管理。Terminus安......
  • C++和C中的输入输出总结、标准输入/标准输出/标准错误与重定向
    标准输入/标准输出/标准错误与重定向0表示标准输入。1表示标准输出。2标准错误。1和2都是默认是输出到屏幕。linux中的>>、>、<、<<:这些符号是Linux中用于重定向输入和输......
  • TensorRT教程(六)使用Python和C++部署YOLOv5的TensorRT模型
    前言 今天这里主要介绍使用Python部署TensorRT的模型以及使用C++部署TensorRT的模型这两种方法。其实在日常部署的工作中,更多是使用C++进行部署,因为这样可以更加丝滑地迁......
  • C++20学习-2 msys2安装
    可以直接从官网下载,但需要配置加速域名,麻烦,可以直接在清华网站上下载。下载站:https://mirrors.tuna.tsinghua.edu.cn/右键配置:msys2配置如何添加右键打开,软件包管理......
  • c++学习9 结构体
    一结构体赋值结构体赋值的方法有三种,逐个成员赋值,整体赋值和拷贝赋值。设一个结构体有struckstudent{intage;charch[32];};逐个成员赋值:studenttony={16,"tony"};......
  • C++栈上创建对象和堆上创建对象
    一、在栈(Stack)上创建对象Student是一个类,创建一个实例化对象:Studentstu;下面进行创建对象指针的操作(非必须):上面代码中创建的对象stu在栈上分配内存,需要使用&获取......
  • 如何一眼分辨是C还是C++
    C语言的历史​C语言是由贝尔实验室的DennisRitchie在20世纪70年代初开发的一种通用程序设计语言。在早期的计算机时代,许多计算机使用不同的汇编语言编写程序,这导致了程序的......
  • C++基于面向对象思想的ATM 系统设计与实现(三级项目)[2023-02-19]
    C++基于面向对象思想的ATM系统设计与实现(三级项目)[2023-02-19]实验二基于面向对象思想的ATM系统设计与实现(三级项目)一、实验目的:(1)掌握派生类的使用方法。(2)......
  • PAT-basic-1025 反转链表 java c++
    一、题目给定一个常数 K 以及一个单链表 L,请编写程序将 L 中每 K 个结点反转。例如:给定 L 为1→2→3→4→5→6,K 为3,则输出应该为3→2→1→6→5→4;如果 K ......