universal initialization语法使得C++对变量对象的定义和初始化与C相比发生了明显的变化,更加方便与灵活。
如下代码所示:
--------cpp---------
int(1);
int x(1);
int{1};
int x3{2};
int x1[5]{1,2,3,4,5};
auto *p = new int[3]{1, 2};
这些语法在c语言中都是不成立的,但是再c++中都是可以的。
用()和{}等价于在C中的=号操作;
()是给基本类型变量用来初始化,{}是用来给自定义或官方的类(也是一种类型,不过不是基本类型)的对象初始化,{}包含了(),可以用()初始化的地方都可以用{}代替,但是{}不能用()代替。
格式:基本类型() 就可以表示申请了一个基本类型大小的内存,不用向C中那样必须要一个变量名,如下:
--------cpp---------
int(); //没有变量名,就向内存中申请了一块空间,没有初始化
int(1); //没有变量名,就向内存中申请了一块空间,初始化为1
int x(1); //也可以用变量名向内存中申请一块空间,初始化为1
int{1};
int x3{2};
格式:类名 {} 表示申请了一个类大小的内存(这里的类就相当于自定义的类型),与c中相似的语法就是结构体
如下代码:
首先定义了一个point类
#include <iostream>
#include <string>
#include<vector>
using namespace std;
struct point
{
int x;
int y;
point() = default;
point(int z) : x{z}, y(z){
cout << "initial construct\n";
};
point(point &p)
{
cout << "copy construct\n";
}
};
使用代码:
point ();//没有对象名,申请了一个point类大小的内存,调用了缺省构造函数初始化,一般
point p(); //有对象名,申请了一个point类大小的内存,调用了缺省构造函数初始化
point {};
point p4{};
point {4};//没有对象名,申请了一个point类大小的内存,调用了参数构造函数point(int z)初始化
point p6{4};//有对象名,申请了一个point类大小的内存,调用了参数构造函数point(int z)初始化
auto *p2 = new point[3]{1, 2};
point[3]{1, 2};//申请数组这种形式是错的,必须加上数组名,上面用new的也可以
point p6{4,2};使用这种形式初始化,如果类point中什么构造函数都没有,则该初始化直接对公共区域的成员变量赋值
struct point
{
int x;
int y;
//这里什么构造函数都没有,复制,析构都没
};
point p6{4,2};//4赋给x,2赋给y
如果point类中有复制构造函数,则是调用复制构造函数来赋值(这个时候就相当于将大括号变为小括号,与调用构造函数一样),如下:
struct point
{
int x;
int y;
point(int z):x(z),y{z}{}//这里构造函数的参数列表里用{}就是赋值
};
point p6{4};//4赋给z,z赋给x和y.
一般没有变量名或对象名的操作使用在返回值return ,
其它地方还是要有名字来操作。
一.返回值中的使用
直接在类型的后面接上一对大括号,大括号里面写每个构造函数参数的值,或者没有构造函数的情况下写每个成员变量的值,然后这一个整体就构成一个表达式,返回一个这个类型的实例.
Vector operator+(Vector a,Vector b)
{
return Vector{a.x+b.x,a.y+b.y};//没有对象名,但是已经生成了一个对象
}
如果上述不用{}通用初始化语法,则需要在函数中实例化一个对象,最后return这个对象。如下: 显然这种方法较为麻烦。
Vector operator+(Vector a,Vector b)
{
Vector c;
c.x=a.x+b.x;
c.y=a.y+b.y;
return c;
}
这里边有个小bug,返回类的对象时应该会调用复制构造函数,但是这里没有
引申一下:
一般有三种情况会调用复制构造函数:
1.当用类一个对象去初始化另一个对象时。point a = b;或point a(b);
2.如果函数形参是类对象。void test(point p){}
3.如果函数返回值是类对象,函数执行完成返回调用时。
point test()
{
point p;
return p ;
}
point test()
{
return point{} ;
}
前两种经过测试都会调用复制构造函数,维度第三个不行。后查找资料得到结果:
参考文章
2.类的实例化对象初始化
下图代码
Point a{1,2}; 就直接将类的成员变量进行了初始化;
如果不用{}通用初始化语法,用如下语法:
Point a(1,2);也可以初始化,这个时候调用的是类的构造函数对它初始化,在类中要写好构造函数才行。
#include <iostream>
#include <string>
using namespace std;
/* 请在这里定义struct */
struct Point
{
int x;
int y;
};
struct Vector
{
int x;
int y;
};
Vector operator+(Vector a,Vector b)
{
return Vector{a.x+b.x,a.y+b.y};
}
Point operator+(Point a,Vector b)
{
return Point{a.x+b.x,a.y+b.y};
}
Point operator+(Vector a,Point b)
{
return Point{a.x+b.x,a.y+b.y};
}
int main()
{
Point a{1,2}; //
Vector b{3,4};
auto x = b+b;
cout<< "b + b = {"<<x.x<<", "<<x.y<<"}"<<endl;
auto y = a+b;
cout<< "a + b = {"<<y.x<<", "<<y.y<<"}"<<endl;
auto z = b+a;
cout<< "b + a = {"<<z.x<<", "<<z.y<<"}"<<endl;
return 0;
}
3.模本类Vector(动态数组)
vector的常见使用方法
vector<类型>对象名(数组长度,元素初值);
vector<int> a(10,1);//定义了一个大小为10的整型动态数组,初始化全部为1
这种模板类也是用构造函数进行初始化的;
用new申请动态数组:
int *a=new int[n];//动态分配n个整型长度的内存给a,这个数组名就为a
int *a=new int; //动态分配了一个整型内存,把地址给a,没有初始化
int *a=new int(1);//动态分配了一个整型内存,把地址给a,将这个内存初始化为1
int *a=new int{1};//与上述同样的效果
Line *line;
line = new Line();//动态分配了一个类Line内存,把地址给line,调用这个类的构造函数将这个内存初始化
line = new Line{}//这个与上面是同样的效果,也会调用构造函数初始化
4.用new动态分配
#include <iostream>
#include <string>
using namespace std;
struct point
{
int x;
int y;
//point(int z) : x{z}, y(z){};
};
int main()
{
auto p = new point[3]{{1,2},{3},{5,6}};
auto p1 = new point{1,2};
cout << p[1].y << endl;
return 0;
}