下面就来补充一下c++雷和对象最后一点内容.
首先先补充一下上一篇博客上c++类和对象(下篇)上-CSDN博客最后学习的静态成员变量的小练习求1+2+3+...+n_牛客题霸_牛客网 (nowcoder.com)下面就是题解.灵活的运用了静态成员变量不销毁的特点,建立数组利用构造函数来完成n次相加.
class A{
public:
A()
{
_sum+=_a;
++_a;
}
static int Getsum()
{
return _sum;
}
private:
static int _a;
static int _sum;
};
int A::_a=1;
int A::_sum=0;
class Solution {
public:
int Sum_Solution(int n) {
A arr[n];
return arr[0].Getsum();
}
};
下面我们开始今天的学习.
友元
其实在日期类中重载<<,>>操作符是已经使用过友元函数了.下面就让我们好好的了解一下友元.
友元提供了⼀种突破类访问限定符封装的⽅式,友元分为:友元函数和友元类,在函数声明或者类声明的前⾯加friend,并且把友元声明放到⼀个类的里面.
友元函数:外部友元函数可访问类的私有和保护成员,友元函数仅仅是⼀种声明,他不是类的成员函数.友元函数可以在类定义的任何地⽅声明,不受类访问限定符限制.只是声明.且⼀个函数可以是多个类的友元函数.
友元类:如果A是B的友元类,那么A可以访问B中的私有和保护成员.友元类的关系是单向的,不具有交换性,⽐如A类是B类的友元,但是B类不是A类的友元.友元类关系不能传递,如果A是B的友元, B是C的友元,但是A不是C的友元.(互为友元要声明和定义分离,不然会有定义在上面的那个找不到下面的成员的问题)
虽然友元可以提供便利,但是友元破坏了封装,所以友元尽量不要多用.
一点点相关练习(注释是我的易错点)
//要先声明,不然A不认识B
class B;
class A
{
friend void Func(A& a, B& b);
public:
A(int a1,int a2)
{
_a1 = a1;
_a2 = a2;
}
private:
int _a1 = 0;
int _a2 = 0;
};
class B
{
friend void Func(A& a, B& b);
public:
B(int b1)
{
_b1 = b1;
}
private:
int _b1 = 0;
};
void Func(A& a, B& b)
{
cout << a._a1 << " " << a._a2 << endl;
cout << b._b1<< endl;
}
int main()
{
A a= { 5,6 };
B b = 2;
Func(a, b);
return 0;
}
#define _CRT_SECURE_NO_WARNINGS 1
#include<iostream>
using namespace std;
class A
{
friend void Func(A& a);
public:
A(int a1, int a2)
:_a1(a1)
,_a2(a2)
{
}
private:
int _a1 = 0;
int _a2 = 1;
};
void Func(A&a)
{
cout << a._a1 << " " << a._a2 << endl;
}
int main()
{
A a= { 5,6 };
Func(a);
return 0;
}
#define _CRT_SECURE_NO_WARNINGS 1
#include<iostream>
using namespace std;
class Time
{
friend class Date;
public:
Time(int hour=8)
:_hour(hour)
{
}
private:
int _hour;
};
class Date
{
public:
Date(int year = 2025, int month = 3, int day = 19)
:_year(year)
, _month(month)
, _day(day)
//,_hour(hour)
{
}
void Func(Time& t)
{
cout << t._hour<<endl;
cout << Time()._hour << endl;
//cout<<_hour<<endl
// 会有为识别_hour的报错
//_hour不可以在友元类中直接使用,要先创建出自己类的对象在使用,或用匿名对象来使用才可以
//也不可以直接在构造函数中直接用初始化列表来初始化_hour
}
private:
int _year;
int _month;
int _day;
};
int main()
{
Time t;
Date d;
d.Func(t);
return 0;
}
内部类
如果⼀个类定义在另⼀个类的内部,这个内部类就叫做内部类.内部类是⼀个独立的类,跟定义在全局相比,他只是受外部类类域限制和访问限定符限制,所以外部类定义的对象中不包含内部类.(用sizeof计算时只算自己的类的大小).且内部类默认是外部类的友元类.(内部类可以访问外部类的成员变量但是外部类却不能访问内部类的成员函数).
内部类本质也是⼀种封装,当A类实现出来主要就是给B类使用,那么可以考虑把A类设计为B的内部类,如果放到private/protected位置,那么A类就是B类的专属内部类,其他地方都用不了.(主意和友元做区分,友元不受访问限定符的限制.)
class A
{
public:
class B
{
public:
void Fuc(const A&a)
{
cout << a.a1 << " " << a2 << endl;
}
private:
int b = 0;
};
private:
int a1 = 0;
static int a2;
};
int main()
{
cout << sizeof(A) << endl;
A a;
//B b;
//没有突破类域所以没办法找到B这个类
A::B b;
b.Fuc(a);
return 0;
}
class A
{
public:
private:
int a1 = 0;
static int a2;
class B
{
public:
void Fuc(const A& a)
{
cout << a.a1 << " " << a2 << endl;
}
private:
int b = 0;
};
};
int main()
{
cout << sizeof(A) << endl;
A a;
//B b;
//没有突破类域所以没办法找到B这个类
//A::B b;
//b.Fuc(a);
//定义为private后就不能在类外访问了
return 0;
}
匿名对象
用 类型(实参) 定义出来的对象叫做匿名对象,而之前我们定义的 类型 对象名(实参) 定义出来的叫有名对象.匿名对象⽣命周期只在当前一行,即用即销毁.(在向链表/顺序表中插入数据时很好用).
一点点相关代码
class A
{
public:
A(int a = 0)
:_a(a)
{
cout << "A(int a)" << endl;
}
~A()
{
cout << "~A()" << endl;
}
private:
int _a;
};
int main()
{
A(1);
return 0;
}
对象拷贝时的编译器优化(了解)
现代编译器会为了尽可能提⾼程序的效率,在不影响正确性的情况下会尽可能减少⼀些传参和传返 回值的过程中可以省略的拷⻉,但是在c++标准中却没有定义如何优化.一般看编译器,下面简单的了解下几种适中的编译器优化.(通常会比下面说的更优化)
1.传值传参下同一行中连续的构造+拷贝构造->直接构造
2.传值返回,连续构造+拷贝构造->直接构造
以上就是我所学习的类和对象的全部内荣啦,类和对象暂时告一段落了.大家晚安