文章目录
目录
- 文章目录
- 前言
- 一、对匿名对象的解读
- 二、匿名对象的对象类型
- 三、匿名对象的使用
- 总结
前言
在C++中,匿名对象是指在没有呗命名的情况下创建的临时对象。它们通常在单个语句中执行一系列操作或调用某个函数,并且不需要将结果存放进变量中。
匿名对象的创建非常简单,在类名后加一对括号,匿名对象就诞生了
一、对匿名对象的解读
匿名对象的结构:
类名();
class A
{
public:
A(int a = 0)
:_a(a)
{
cout << "A()" << endl;
}
~A()
{
cout << "~A()" << endl;
}
private:
int _a;
};
int main()
{
A a; //有名对象
A(10); //匿名对象
A b(10);//有名对象
return 0;
}
测试运行:
对于有名对象而言,生命周期在函数局部域中
对于匿名对象而言,生命周期就在当行,过了当行它就会调用析构函数,结束它的生命
二、匿名对象的对象类型
匿名对象不仅可以是类类型,也可以是内置类型,例:int,double等
例:
int main()
{
cout << int() << endl; // 0
cout << double() << endl; // 0
return 0;
}
这里注意本来C++语法规定,内置类型是没有构造函数的,但是有了模板之后,系统对这里进行了特殊处理,内置类型也有了构造函数,这样使得内置类型也有匿名对象了
从这里可以知道,内置类型的匿名对象不给值初始化都是0
接下来我们来看看类类型和内置类型的混合使用
我们在来看一下
模板参数通过模板匿名对象赋予缺省值
Print<int>(10); // 十个0
Print<double>(10); //空
三、匿名对象的使用
简单使用场景:
class A
{
public:
int testA(size_t n)
{
cout << "testA" << endl;
return n;
}
};
int main()
{
//正常调用
A a;
a.testA(10);
//匿名对象调用
A().testA(1);
return 0;
}
如果你只需要调用一次函数那么显然使用匿名对象去调用是便利一些的,但是你还想多次调用类中的对象,这里应该使用有名对象
复杂使用场景:
A& ret = A(10);
直接这样写编译器会报错,因为匿名对象的生命周期只在这一行,因为匿名对象和临时对象一样具有常性,所以这里涉及到权限放大的问题
解决方法:在这条语句前面加上const
const A& ret = A(10);
现在这条语句就属于权限的平移,我们知道只要涉及引用,就需要注意权限放大,缩小,平移的问题,权限可以平移和缩小,但是不能放大,所以这条语句是成立的
好了,这个问题解决了,那么如我们上面所说,匿名对象的生命周期只在当行,此时ret是否会指向一块被释放的空间变成野引用呢!
我们来测试一下
可以看到匿名对象并没有立马调用析构函数进行释放
这里其实就是加上了const修饰的原因,使得匿名对象延长了生命周期,只有当ret使用结束之后,即程序结束之后,它才会销毁
匿名函数对于string类的使用:
void push_back(const string& s)
{
cout << s << endl;
}
//1
string s1("nxbw");
push_back(s1);
//2
push_back(string("nxbw"));
//3
push_back("nxbw");
第一种是:实例化一个对象,然后使用对象作为参数进行调用
第二种是:使用匿名对象直接进行调用
第三种是:字符串类型隐式类型转换为string类型,进行调用
给push_back的参数加上const,此时即可以接收普通变量也可以接收常引用,提高了代码的健壮性
总结
1.匿名对象生命周期只在当行,过了当行就会调用析构函数析构,所以无法持续使用
2.匿名对象可以是自定义类型也可以是内置类型
3.匿名对象也有自己的构造函数,析构函数和成员函数它们的行为和有名对象一样,但是匿名对象没有名称,所以无法直接访问它们