1. 程式人生 > >類中陣列成員變數怎麼初始化,陣列名與指標的區別

類中陣列成員變數怎麼初始化,陣列名與指標的區別

使用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),最後取出對應記憶體中的字元,其他的資料型別一次類推。