構造函數體賦值
之前學習瞭解到,在創建對象的時候,編譯器會通過調用構造函數,給對象中的各個成員變量賦一個合適的初始值。
class d
{
pubilc:
d(int a,int b,int c)
{
_a = a;
_b = b;
_c = c;
}
private:
int _a;
int _b;
int _c;
};
雖然上述構造函數調用之後,對象中已經有了一個初始值,但是不能將其稱作爲類對象成員的初始化,構造函數體中的語句只能將其稱作爲賦初值,而不能稱作初始化。因爲初始化只能初始化一次,而構造函數體內可以多次賦值。所以,我們引進了初始化列表
初始化列表
以一個冒號開始,接着是一個以逗號分隔的數據成員列表,每個"成員變量"後面跟一個放在括 號中的初始值或表達式比如:
class d
{
pubilc:
d(int a,int b,int c)
:_a(a),
_b(b),
_c(c)
{}
private:
int _a;
int _b;
int _c;
};
注意:
1. 每個成員變量在初始化列表中只能出現一次(初始化只能初始化一次)
2. 類中包含以下成員,必須放在初始化列表位置進行初始化:
引用成員變量,const成員變量,自定義類型成員(該類沒有默認構造函數)
class A
{
public:
A(int a)
:_a(a)
{}
private:
int _a;
};
class d
{
pubilc:
d(int a,int b,int c)
:_aa(a),
_b(b),
_c(10)
{}
private:
A _aa;//自定義變量
int& _b;//引用
const int _c;//const
};
3. 儘量使用初始化列表初始化,因爲不管你是否使用初始化列表,對於自定義類型成員變量,一定會先使用初始化列表初始化。
4. 成員變量在類中聲明次序就是其在初始化列表中的初始化順序,與其在初始化列表中的先後次序無關
.
static成員
聲明爲static的類成員稱爲類的靜態成員,用static修飾的成員變量,稱之爲靜態成員變量;用static修飾的 成員函數,稱之爲靜態成員函數。靜態的成員變量一定要在類外進行初始化
static int getCount()
{
//
/*Display();
cout << _year << endl;*/
return cnt;
}
1.靜態成員函數: 函數內部沒有this指針
2.靜態成員函數不能訪問非靜態成員函數/變量–>因爲非靜態成員需要this指針,但是靜態成員函數內部缺少this指針,所以不能訪問.
3.非靜態成員函數可以訪問靜態成員函數/變量
4. 靜態成員變量, 所有對象共享此成員變量, 可以看成類成員
靜態成員變量不能在聲明的時候給默認
靜態成員不在對象模型中,一般存放在數據段, 不能在初始化列表中初始化
class Date
{
public:
Date(int year = 2020, int month = 12, int day = 25)
:_year(year)
, _month(month)
, _day(day)
{
++cnt;
cout << "Date(int,int,int)" << endl;
}
Date(const Date& d)
:_year(d._year)
, _month(d._month)
, _day(d._month)
{
++cnt;
cout << "Date(const Date&)" << endl;
}
//靜態成員函數: 函數內部沒有this指針
static int getCount()
{
return cnt;
}
void Display()
{
cout << _year << "-" << _month << "-" << _day << endl;
getCount();
cout << cnt << endl;
}
private:
int _year = 1;
int _month = 1;
int _day = 1;
public:
static int cnt;
};
靜態成員變量/靜態成員函數訪問方式:
- 對象訪問
cout << d.getCount() << endl;
cout << d2.getCount() << endl;
cout << &d.cnt << endl;
cout << &d2.cnt << endl;
- 類名 + 作用域限定符
cout << &Date::cnt << endl;
cout << Date::cnt << endl;
cout << Date::getCount() << endl;
友元
友元分爲:友元函數和友元類
友元提供了一種突破封裝的方式,有時提供了便利。但是友元會增加耦合度,破壞了封裝,所以友元不宜多用。
友元函數可以直接訪問類的私有成員,它是定義在類外部的普通函數,不屬於任何類,但需要在類的內部聲 明,聲明時需要加friend關鍵字。
class Date
{
public:
//友元函數
friend ostream& operator<<(ostream& outputS, Date& d);
friend istream& operator >> (istream& inputS, Date& d);
Date(int year = 2020, int month = 12, int day = 25)
:_year(year)
, _month(month)
, _day(day)
{}
Date(const Date& d)
:_year(d._year)
, _month(d._month)
, _day(d._month)
{}
private:
int _year = 1;
int _month = 1;
int _day = 1;
};
ostream& operator<<(ostream& _cout, const Date& d)
{
_cout<<d._year<<"-"<<d._month<<"-"<<d._day;
return _cout;
}
istream& operator>>(istream& _cin, Date& d)
{
_cin>>d._year;
_cin>>d._month;
_cin>>d._day;
return _cin;
}
說明:
1. 友元函數儘量少用,它是一種突破封裝的語法
2. 友元函數: friend + 正常函數的定義/聲明
3. 友元函數可以訪問類的私有成員
4. 友元函數不是類的成員函數,它是普通的非成員函數
5. 只需要在類中聲明友元函數,不需要在類中定義
class Date
{
public:
friend ostream& operator<<(ostream& outputS, Date& d);
friend istream& operator >> (istream& inputS, Date& d);
friend class B;//定義B爲Date的友元類
Date(int year = 2020, int month = 12, int day = 25)
:_year(year)
, _month(month)
, _day(day)
{}
private:
int _year;
int _month;
int _day;
};
class B
{
public:
//disPlay, fun, fun1都爲Date類的的友元函數
void disPlay(const Date& d)
{
cout << d._year << d._month << d._day << endl;
}
void fun(const Date& d)
{
cout << d._year << d._month << d._day << endl;
}
void fun1(const Date& d)
{
cout << d._year << d._month << d._day << endl;
}
};
說明:
- 如果一個類是另一個類的友元類,則此類中的所有成員函數即爲另一個類的友元函數
- 友元關係不能傳遞
- 友元類的所有成員函數都可以訪問另一個類中的非公有成員。
內部類
概念:如果一個類定義在另一個類的內部,這個內部類就叫做內部類。注意此時這個內部類是一個獨立的 類,它不屬於外部類,更不能通過外部類的對象去調用內部類。外部類對內部類沒有任何優越的訪問權限。
注意:內部類就是外部類的友元類。注意友元類的定義,內部類可以通過外部類的對象參數來訪問外部類中 的所有成員。但是外部類不是內部類的友元。
特性:
1.內部類可以定義在外部類的public、protected、private都是可以的。
2.注意內部類可以直接訪問外部類中的static、枚舉成員,不需要外部類的對象/類名。
3.sizeof(外部類)=外部類,和內部類沒有任何關係。
class A
{
private:
static int k;
int h;
public:
class B
{
public:
void foo(const A& a)
{ 、
cout << k << endl;//OK
cout << a.h << endl;//OK
}
};
};
int A::k = 1;
int main()
{
A::B b;
b.foo(A());
return 0;
}