類中陣列成員變數怎麼初始化,陣列名與指標的區別
使用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),最後取出對應記憶體中的字元,其他的資料型別一次類推。