参考书籍:

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;
}