自学内容网 自学内容网

C++从入门到起飞之——友元&内部类&匿名对象 全方位剖析!

🌈个人主页:秋风起,再归来~
🔥系列专栏:C++从入门到起飞          
🔖克心守己,律己则安

目录

1、友元

2、内部类

3. 匿名对象

4、完结散花


1、友元

• 友元提供了⼀种突破类访问限定符封装的⽅式,友元分为:友元函数友元类,在函数声明或者类 声明的前⾯加friend,并且把友元声明放到⼀个类的⾥⾯

友元类:

class A
{
public:
//B是A的友元类
friend class B;
private:
int _a1 = 1;
int _a2 = 2;
};

class B
{
public:
B()
{
//......
}
void func(const A& aa)
{
//访问A的私有成员
cout << aa._a1 << endl;
cout << aa._a2 << endl;
}
private:
int _b1 = 3;
int _b2 = 4;
};

int main()
{
A aa1;
B bb1;
bb1.func(aa1);
return 0;
}

 友元函数:

class A
{
public:
//B是A的友元类(友元声明)
friend class B;
//func是A类的友元函数(友元声明)
friend void func(const A& aa);
private:
int _a1 = 1;
int _a2 = 2;
};

void func(const A& aa)
{
cout << aa._a1 << endl;
cout << aa._a2 << endl;
}

外部友元函数可访问类的私有和保护成员,友元函数仅仅是⼀种声明,他不是类的成员函数

• 友元函数可以在类定义的任何地⽅声明,不受类访问限定符限制

• ⼀个函数可以是多个类的友元函数

// 前置声明,不然A的友元函数声明编译器不认识B
class B;

class A
{
public:
//B是A的友元类(友元声明)
friend class B;
//func是A类的友元函数(友元声明)
friend void func(const A& aa,const B& bb);
private:
int _a1 = 1;
int _a2 = 2;
};

class B
{
public:
friend void func(const A& aa, const B& bb);
private:
int _b1 = 3;
int _b2 = 4;
};

void func(const A& aa, const B& bb)
{
cout << aa._a1 << endl;
cout << aa._a2 << endl;
cout << bb._b1 << endl;
cout << bb._b2 << endl;
}

int main()
{
A aa1;
B bb1;
func(aa1,bb1);
return 0;
}

友元类中的成员函数可以是另⼀个类的友元函数,都可以访问另⼀个类中的私有和保护成员。 • 友元类的关系是单向的,不具有交换性,⽐如A类是B类的友元(A可以访问B的私有或保护成员,但B不可以),但是B类不是A类的友元。

• 友元类关系不能传递,如果A是B的友元,B是C的友元,但是A不是B的友元。

• 有时提供了便利。但是友元会增加耦合度,破坏了封装,所以友元不宜多⽤。

2、内部类

• 如果⼀个类定义在另⼀个类的内部,这个内部类就叫做内部类。内部类是⼀个独⽴的类定义在 全局相⽐,他只是受外部类类域限制访问限定符限制,所以外部类定义的对象中不包含内部类

• 内部类默认是外部类的友元类(即内部类可以访问外部类的私有和保护成员)。


class A
{
public:
//内部类
class B//默认是A的友元类
{
public:
void func(A& aa)
{
A::a++;
aa.b++;//访问A类的私有成员
}
private:
int b1 = 1;
int b2 = 2;
};
private:
static int a;
int b = 1;
};

int main()
{
A a;
cout << sizeof(a) << endl;
return 0;
}

a对象的大小是4说明B类是一个独立的类 ,外部类定义的对象中不包含内部类!

• 内部类本质也是⼀种封装,当A类跟B类紧密关联,A类实现出来主要就是给B类使⽤,那么可以考 虑把A类设计为B的内部类,如果放到private/protected位置,那么A类就是B类的专属内部类,其 他地⽅都⽤不了。

上篇文章的OJ题就可以用内部类来进行封装!

求1+2+3+...+n_⽜客题霸_⽜客⽹

描述

求1+2+3+...+n,要求不能使用乘除法、for、while、if、else、switch、case等关键字及条件判断语句(A?B:C)。

数据范围:0<n≤200
进阶: 空间复杂度 O(1) ,时间复杂度 O(n)

示例1

输入:

5

复制返回值:

15

示例2

输入:

1

复制返回值:

1

OJ链接

class Solution 
{
    class Sum
    {
    public:
        Sum()
        {
            ret+=i;
            ++i;
        }
    };
    static int i;
    static int ret;
public:
    int Sum_Solution(int n)
    {
        //Sum a[n];变长数组
        //创建n个对象来调用n次构造函数
        Sum* p=new Sum[n];
        return ret;
    }
   
};
//用静态的成员变量来记录结果
int Solution::i=1;
int Solution::ret=0;

3、 匿名对象

• ⽤类型(实参)定义出来的对象叫做匿名对象相⽐之前我们定义的类型对象名(实参)定义出来的 叫有名对象

• 匿名对象⽣命周期只在当前⼀⾏,⼀般临时定义⼀个对象当前⽤⼀下即可,就可以定义匿名对象。

class A
{

};

int main()
{
A();//定义的匿名对象,生命周期只存在当前这一行
}
class A
{
public:
A(int a = 0)
:_a(a)
{
cout << "A(int a)" << endl;
}
~A()
{
cout << "~A()" << endl;
}
private:
int _a;
};
class Solution {
public:
int Sum_Solution(int n) {
//...
return n;
}
};
int main()
{
A aa1;
// 不能这么定义对象,因为编译器⽆法识别下⾯是⼀个函数声明,还是对象定义
//A aa1();
// 但是我们可以这么定义匿名对象,匿名对象的特点不⽤取名字,
// 但是他的⽣命周期只有这⼀⾏,我们可以看到下⼀⾏他就会⾃动调⽤析构函数
A();
A(1);
A aa2(2);
// 匿名对象在这样场景下就很好⽤,当然还有⼀些其他使⽤场景,这个我们以后遇到了再说
Solution().Sum_Solution(10);
return 0;
}

4、完结散花

好了,这期的分享到这里就结束了~

如果这篇博客对你有帮助的话,可以用你们的小手指点一个免费的赞并收藏起来哟~

如果期待博主下期内容的话,可以点点关注,避免找不到我了呢~

我们下期不见不散~~

​​​​


原文地址:https://blog.csdn.net/2301_80221228/article/details/140729988

免责声明:本站文章内容转载自网络资源,如本站内容侵犯了原著者的合法权益,可联系本站删除。更多内容请关注自学内容网(zxcms.com)!