💗个人主页💗
⭐个人专栏——C++学习⭐
💫点击关注🤩一起学习C语言💯💫
目录
1. 友元
1.1 友元函数
1.2 友元类
2. 内部类
2.1 成员内部类
2.2 局部内部类
3. 匿名对象
3.1 基本概念
3.1 隐式转换
1. 友元
友元提供了一种突破封装的方式,有时提供了便利。但是友元会增加耦合度,破坏了封装,所以 友元不宜多用。
友元分为:友元函数和友元类。
1.1 友元函数
友元函数可以访问类的私有成员和受保护成员,即使它们不是类的成员函数。
友元函数在类中声明为友元,可以在类外部定义,但是它们可以访问类的私有和受保护成员。
友元函数的声明方式为将函数声明在类的声明内部,但不是类的成员函数,并使用关键字"friend"来标识它。
在类的外部定义友元函数时,不需要使用类名限定,直接定义即可。
class MyClass
{
private:int num;
public:MyClass(int n) : num(n) {}friend void printNum(const MyClass& obj);
};void printNum(const MyClass& obj)
{cout << "Num: " << obj.num << endl; // 可以访问类的私有成员num
}int main()
{MyClass obj(10);printNum(obj); // 调用友元函数return 0;
}
友元函数的使用场景包括:
- 当某个函数需要访问类的私有成员时,可以将该函数声明为类的友元函数。
- 当需要重载运算符时,可以将重载函数声明为类的友元函数。
- 当需要在类的各个对象之间进行相互操作或访问私有数据时,可以使用友元函数。
友元函数的一个重要限制是,在类的声明内部声明为友元函数的函数需要在类之外定义。因此,友元函数不能直接访问类的成员变量和成员函数,需要使用对象的引用或指针来访问。
1.2 友元类
友元类的所有成员函数都可以是另一个类的友元函数,都可以访问另一个类中的非公有成员。
- 友元关系是单向的,不具有交换性。
- 友元关系不能传递 如果C是B的友元, B是A的友元,则不能说明C时A的友元。
- 友元关系不能继承,在继承位置再给大家详细介绍。
class ClassA
{
private:int numA;
protected:int numB;
public:ClassA(int a, int b) : numA(a), numB(b) {}friend class ClassB;
};class ClassB
{
public:void printNum(const ClassA& obj) {cout << "NumA: " << obj.numA << endl; // 可以访问类A的私有成员numAcout << "NumB: " << obj.numB << endl; // 可以访问类A的受保护成员numB}
};int main()
{ClassA objA(10, 20);ClassB objB;objB.printNum(objA); // 调用友元类的成员函数return 0;
}
友元类的使用场景包括:
- 当一个类需要访问另一个类的私有成员时,可以将该类声明为友元类。
- 当需要在类之间进行相互操作或访问私有数据时,可以使用友元类。
2. 内部类
概念:如果一个类定义在另一个类的内部,这个内部类就叫做内部类。内部类是一个独立的类, 它不属于外部类,更不能通过外部类的对象去访问内部类的成员。外部类对内部类没有任何优越 的访问权限。
注意:内部类就是外部类的友元类,参见友元类的定义,内部类可以通过外部类的对象参数来访 问外部类中的所有成员。但是外部类不是内部类的友元。
内部类可以分为两种类型:成员内部类和局部内部类。
特性:
- 内部类可以定义在外部类的public、protected、private都是可以的。
- 注意内部类可以直接访问外部类中的static成员,不需要外部类的对象/类名。
- sizeof(外部类)=外部类,和内部类没有任何关系。
2.1 成员内部类
成员内部类是在外部类的内部定义的一个类,它可以访问外部类的所有成员,包括私有成员。
成员内部类的定义通常放在外部类的声明中,但是它的实现需要在外部类的作用域之外进行。
class OuterClass
{
private:int _x;static int y;
public:OuterClass(int x = 10):_x(x){}class InnerClass{public:void display(OuterClass obj){cout << "x = " << obj._x << endl;cout << "y = " << y << endl;}};
};int OuterClass::y = 0; // 静态成员变量初始化int main() {OuterClass obj1;OuterClass::InnerClass obj2;obj2.display(obj1);return 0;
}
2.2 局部内部类
局部内部类是在函数或代码块内定义的一个类,它只在该函数或代码块的作用域内可见。
局部内部类可以访问外部类的所有成员,包括私有成员。
void outerMethod()
{class LocalClass {public:void display() {cout << "This is a local inner class" << endl;}};LocalClass obj;obj.display();
}int main()
{outerMethod();return 0;
}
3. 匿名对象
3.1 基本概念
匿名对象是指在创建对象时,没有为对象指定一个具体的名称,而是直接使用对象执行操作或调用方法。匿名对象在使用后就被销毁,无法再次引用。
class MyClass
{
public:void display() {cout << "This is a MyClass object" << endl;}
};int main()
{// 创建一个匿名对象并调用其display()方法MyClass().display();return 0;
}
3.1 隐式转换
C++中的匿名对象可以进行隐式转换。
隐式转换是指在某些情况下,编译器会自动将一个对象转换为目标类型,而无需显式地使用类型转换操作符。
1. 赋值操作:可以将匿名对象直接赋值给另一个对象。
class MyClass
{
public:MyClass(int value) : m_value(value) {}int getValue() { return m_value; }
private:int m_value;
};int main() {MyClass obj = MyClass(10); // 匿名对象被隐式转换并赋值给objcout << obj.getValue(); // 输出:10return 0;
}
2. 函数返回值:一个函数可以返回一个匿名对象,并且该匿名对象会被隐式转换为函数返回类型。
class MyClass
{
public:MyClass(int value) : m_value(value) {}int getValue() { return m_value; }
private:int m_value;
};MyClass createObject()
{return MyClass(10); // 返回一个匿名对象
}int main()
{MyClass obj = createObject(); // 匿名对象被隐式转换并赋值给objcout << obj.getValue(); // 输出:10return 0;
}
3. 表达式中的运算:在一些表达式中,匿名对象可以参与运算,并且会被隐式转换为相应的类型。
class MyClass
{
public:MyClass(int value) : m_value(value) {}int getValue() { return m_value; }MyClass operator +(const MyClass& other) {return MyClass(m_value + other.m_value); // 返回一个匿名对象}
private:int m_value;
};int main()
{MyClass obj1(10);MyClass obj2(20);MyClass result = obj1 + obj2; // 匿名对象参与运算并被隐式转换为MyClasscout << result.getValue(); // 输出:30return 0;
}