类中数组成员变量怎么初始化,数组名与指针的区别使⽤STL标准模板库之后,编程时已经很少使⽤数组和指针,相反,多使⽤序列容器vector代替之。
(std::vector<int>,构造函数接受const std::vector<int> &vec,拷贝⽤this->arr= vec 即可)
但事实并不这么理想,在迫不得已的情况下,我们还是会选择使⽤数组。
今天刷Leetcode想了⼀个问题:当数组作为类的成员变量时,应该怎么对它(数组)进⾏初始化。
例如:
class ObjectB{};
class ObjectA{
public:
ObjectB array[5];//对象数组作为类的成员
}
⽅法⼀:连续赋值
Class A
{
public:
A();
~A(){};
private:
int abc[3];
}
A::A()
{
for( int nLoop=1;nLoop<=3;nLoop++)
abc[nLoop]=nLoop;
}
但假如需要初始化的是没有默认构造的对象数组⼜如何呢? 例如:
class B
{
public:
B(int a);
~B(){};
private:
int m_nB;
}
B::B(int a): m_nB(a)
{
}
Class A
{
public:
A();
~A(){};
private:
B abc[3];
}
这时该如何初始化呢?
数组作为成员变量时只有默认初始化,也就是⽆法传递参数。有两种变通⽅案:你可以把对象数组改成指针数组,或者把ClassB类的构造和初始化分开。
⽅案⼀:
Class A{
public:
A();
~A(){};
private:
B *abc[3];
}
A::A()
{
abc[0] = new B(1);
abc[1] = new B(2);
abc[2] = new B(3);
}
⽅案⼆:
class ClassB{
private:
int data;
public:
ClassB(int d):data(d){ }
ClassB(){ }
void Init(int d){data=d;}
};
class ClassA{
private:
ClassB arrayOfObjectClassB[2];
public:
ClassA(int i){
arrayObjectOfClassB[0].Init(i);
arrayObjectOfClassB[1].Init(i);
}
};
class ObjectB{};
class ObjectA{
public:
ObjectB array[5];//对象数组作为类的成员
}
那样的话对象数组的初始化会变得很⿇烦,因为数组名不能作为左值,所以不可以指针传递的⽅式赋值。
⽽且不能通过参数列表(构造函数后⾯加⼀个冒号)的⽅式初始化,所以只能让类ObjectA⾃动调⽤类ObjectB的⽆参构造函数.
class ObjectB{
public:
int a;
public:
ObjectB(int m=0)
{
a=m;
}
};
class ObjectA{
public:
ObjectB Array[5];
public:
ObjectA(int *p)
{
Array[0]=ObjectB(p[0]);
Array[1]=ObjectB(p[1]);
Array[2]=ObjectB(p[2]);
}
};
定义数组初始化int main()
{
int p[5]={0,2,2,3,4};
ObjectA am=ObjectA(p);
std::cout<<am.Array[1].a<<std::endl;
return 0;
}
⽅法⼆:声明为静态数组
class A
{
public:
static int arr[3];
};
int A::arr[3]={1,2,3};
int main()
{
A a;
std::cout<<a.arr[0]<<a.arr[1]<<std::endl;
system("pause");
return 0;
}
初始化数组成员变量:似乎没有⽐较简单的办法在初始化列表⾥初始化数组成员。建议在构造函数的函数体内赋值。不过可以⽤模板实现:
class A {
public:
template & Args>
args) : x_{} {}
virtual void foo() {} // 阻⽌aggregate initialization
private:
int x_[4];
};
template <class T, class U, ints>
A FactoryImpl(const T &list, std::integer_sequence<U, >) {
return {list[ints]...};
}
template <class T, size_t N>
auto Factory(const T (&arr)[N]) {
return FactoryImpl(arr, std::make_index_sequence<N>());
}
int main()
{
A x = {1,2,3,4};
A y = Factory({1,2,3,4});
return 0;
}
1.指针和数组名占据的内存空间⼤⼩不⼀样,如下程序:
char str[10];
char *pstr=str;
cout<<
cout<<sizeof
第⼀⾏输出结果是:10,第⼆⾏输出结果是:4
从这⾥我们可以看出:数组名对应着(⽽不是指向)⼀块内存(数组所占的内存区域)或者说是指代数组这种数据结构,其地址与容量在⽣命期内保持不变,只有数组的内容可以改变。指针对应着⼀个占据4个字节(Win32)的内存区域,⽽指向这4个字节所存储的地址所对应的内存单元,它可以指向任意类型的内存块。因此,sizeof(str)值为数组占据的内存空间⼤⼩即10个字节,⽽sizeof(pstr)值为指针的值占据的内存空间⼤⼩即4个字节。
2.数组名不是指针,但是在⼀定的情况下转换为指代数组的⾸地址的指针,⽽这个数组名转为的指针只能是指针常量。
在以下两种情况下才能进⾏这种转换:
a.在程序1第⼆⾏代码中,将数组名直接赋值给指针,此时数组名转换为指向数组的⾸单元的常量指针。
b.直接将数组名作为指针形参的时候,数组名则转换为指向数组的⾸单元的常量指针进⾏传递,如下程序:
void fun(char str[])
{
cout<<str++;
}
void main()
{
…
char str1[5];
fun(str1);
…
}
注意:数组名作为函数形参进⾏传递时,在⼦函数体内,它已经不再是⼀个指针常量,⽽是变成⼀个真正的指针,可以进⾏增减等操作,可以被修改。所以程序2中⼦程序第⼀条语句输出的sizeof(str)的值为4.
既然数组名可以被看作指针常量,⽽常量是不能修改的,那么如下代码是不允许的:
char str[10];
str++;
但如下代码则合法的:
char str[10];
char *pstr=str;
pstr++;
3.使⽤指针访问数组和使⽤数组名访问数组本质不同。
例如:
char str[7]=”ksarea”;
char *pstr=str;
cout<<str[3]<<" "<<pstr[3];
其中 str[3] 和 pstr[3] 返回的都是字符’r',但是编译器产⽣的执⾏代码却不⼀样。对于str[3],执⾏代码是从str开始,向后移动两个字节,然后取出其中的字符;⽽对于pstr[3],执⾏代码是从pstr中取出地址,然后在其上加3,然后取出对应内存中的字符。
当然,如果pstr是指向int型的指针,那么pstr[3]的处理过程是从pstr中取出地址,然后在其上加上3*sizeof(int),最后取出对应内存中的字符,其他的数据类型⼀次类推。
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。
发表评论