目录
[🥝 语法结构](#🥝 语法结构)
一、前言
在**C++**中,**匿名对象(Anonymous Object)是指在没有被命名的情况下创建的临时对象。**它们通常用于在单个语句中执行一系列操作或调用某个函数,并且不需要将其结果存储到变量中。
**匿名对象的创建非常简单,只需在类名后面使用一对空括号。**接下去呢我们来谈一谈C++中的匿名对象,可能你在C语言结构体章节中听说过【匿名结构体】,但是【匿名对象】你有听说过吗?
二、匿名对象的概念详解
🥝 语法结构
【语法格式】:类名()
🍍概念理解
class A {
public:
A(int a)
{
cout << "A构造函数的调用" << endl;
_a = a;
}
~A()
{
cout << "A析构函数的调用" << endl;
}
private:
int _a;
};
-
首先看到这里有一个类A,然后在下面实例化了两个类A的对象,分别使用的是**【有名对象】和【匿名对象】,此时就可以很明显地看出它们的区别之所在,++匿名对象很明显就是没有名字++**
int main(void)
{
A a1(10); // 有名对象 -- 生命周期在当前函数局部域
A(20); // 匿名对象 -- 生命周期在当前行
return 0;
}
👉对于【有名对象】而言,其生命周期在当前函数局部域
👉对于【匿名对象】而言,其生命周期在当前行
- 这一块我们可以通过调试来进行观察,可以发现对于匿名对象执行完当前的这一行就直接去调用析构了,所以它的生命周期之后一行(其实不一定,看下去你就知道了)
那知道了其特性后我们便可以去用一用这个匿名对象呢
三、匿名对象的对象类型
匿名对象不仅可以是类类型,也可以是内置类型,比如int、double 等等
-
首先我们来看一下内置类型的匿名对象
int main()
{
cout << int() << endl; // 0
cout << double() << endl; // 0
return 0;
} -
可以看出,内置类型的匿名对象都是0
接下来,我们将类类型 和 内置类型混合使用,来看看
template<typename T>
void Print(int n , const T& val = T())
{
for (int i = 0; i < n; i++)
{
cout << val << " ";
}
cout << endl;
}
int main()
{
cout << int() << endl; // 0
cout << double() << endl; // 0
Print<int>(5); // 0 0 0 0 0
Print<string>(5); // 空
return 0;
}
四、匿名对象的使用
🍇简单场景的使用
下面有一个类,现在我们要去调用这个类中的成员函数,你会如何去进行调用呢?
class Solution {
public:
int Sum_Solution(int n)
{
cout << "Sum_Solution" << endl;
return n;
}
};
-
相信最常规的做法就是像下面这样,实例化出一个对象,然后通过**对象.函数名()**的形式进行调用
Solution s;
s.Sum_Solution(1); -
但是呢,我直接使用下面这一种形式也可以做到,即【匿名对象】去进行调用,虽然这一种调用形式比较方便,但是呢是存在局限性的,我们只能调用这么一次,若是你想要多次调用类中的这个函数时,就需要去构造【有名对象】了,其生命周期是到程序结束为止的
Solution().Sum_Solution(2);
🍉复杂场景的使用
💬 请问下面这匿名对象可以被引用吗,快速回忆一下C++引用的相关知识
A& ra = A(1);
- 编译一下可以发现是做不到的,如果你【C++引用】这一块学习扎实的话,相信很快就能想到是 权限放大 的问题,那这里为什么会造成权限放大呢?原因就在于这个匿名对象,它和临时对象一样是具有常性的,那一个非常性的对象去引用常性的就会有问题了
-
此时我们只需要在前面加上一个const即可
const A& ra = A(1);
💬 那我现在还想问题,这一块也是涉及引用相关的知识,因为这个匿名对象的生命周期只在这一行,那么此时这个ra是否会变成**【野引用】**呢?即引用了一块已经不存在的空间?
- 其实就是因为这个const常引用的原因,延长了匿名对象的生命周期,那么前面的对象**
ra
**是正常的对象,对这个匿名对象进行了引用即取了别名,那么就会在程序结束的时候才进行销毁
接下去我们再来看第二块,有关STL中的string
-
看到我这里是写了一个函数,形参部分是一个string的常引用
void push_back(const string &s)
{
cout << s << endl;
}
然后我在下面写了调用这个函数的三种形式
-
第一种是实例化对象然后去进行调用
-
第二种采用的就是我们上面所学习的**【匿名对象】**
-
第三种是直接传递了一个**【常量字符串】进去,这中间会产生一个【临时对象】**,然后进行隐式类型转换
-
那你会更喜欢哪种方式呢,不用猜,一定是这第三种方式
// 1
string str("11111");
push_back(str);
// 2
push_back(string("22222"));
// 3
push_back("33333"); -
对于第二种的**【匿名对象】和第三种的【临时对象】,它们都具有一个常属性**,所以在函数的形参部分不可以是普通的引用,不然就会产生一个权限放大的问题,加上**
const
后就是权限平移,****++此时既可以接受普通引用也可以接收常引用,提高了代码的健壮性++**
五、总结
1️⃣: 匿名对象的生命周期非常短暂,只在当前语句中有效。一旦执行到语句结束,匿名对象就会被销毁。因此,无法在后续的代码中再次引用该对象。
2️⃣: 匿名对象的对象可以为:类类型,也可以是内置类型3️⃣: 匿名对象也可以有自己的构造函数、析构函数和成员函数,它们的行为与具名对象一样。但由于匿名对象没有名称,所以无法直接访问它们。
六、共勉
以下就是我对 C++ 匿名对象 的理解,如果有不懂和发现问题的小伙伴,请在评论区说出来哦,同时我还会继续更新对 C++STL库 的理解,请持续关注我哦!!!