使用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的无参构造函数. 

#include <iostream>
#include "stdlib.h"
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;
}

 

另外https://segmentfault.com/q/1010000009255553里面大神的说法,虽然我没看懂。

初始化数组成员变量:似乎没有比较简单的办法在初始化列表里初始化数组成员。建议在构造函数的函数体内赋值。不过可以用模板实现:

#include <cstddef>
#include <utility>

class A {
 public:
  template <class... Args>
    A(Args... args) : x_{args...} {}
  virtual void foo() {} // 阻止aggregate initialization

 private:
  int x_[4];
};

template <class T, class U, size_t... ints>
A FactoryImpl(const T &list, std::integer_sequence<U, ints...>) {
  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;
}

 

转载自:http://www.cppblog.com/luyulaile/archive/2011/02/14/140001.html

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),最后取出对应内存中的字符,其他的数据类型一次类推。

Logo

开放原子开发者工作坊旨在鼓励更多人参与开源活动,与志同道合的开发者们相互交流开发经验、分享开发心得、获取前沿技术趋势。工作坊有多种形式的开发者活动,如meetup、训练营等,主打技术交流,干货满满,真诚地邀请各位开发者共同参与!

更多推荐