1.初始化列表
初始化列表:以一个冒号开始,接着是一个以逗号分隔的数据成员列表,每个”成员变量“后面跟一个放在括号中的初始值或表达式。
class Date1
{
public:
Date1(int year,int month,int day)
:_year(year)
,_month(month)
,_day(day)
{}
private:
int _year;
int _month;
int _day;
};
注意点:
1.每个成员变量在初始化列表只能出现一次(初始化只能初始化一次)
2.类中包含以下成员,必须放在初始化列表进行初始化
引用 成员变量
const成员变量
自定义类型成员(且改类没有默认构造函数)
每个成员变量在初始化列表中只能出现一次,语法理解上初始化列表可以认为是每个成员变量定义初始化的地方。
C++11支持在成员变量声明的位置给缺省值,这个缺省主要是给没有显式在初始化列表初始化成员使用的
尽量使用初始化列表初始化,因为那些不在初始化列表初始化的成员也会走初始化列表,如果这个成员在声明位置给了缺省值,初始化列表会用这个缺省值初始化,如果没有给缺省值,对于没有显式在初始化列表初始化的内置类型成员是否初始化取决于编译器,C++没有规定,对于没有显式在初始化列表的自定义类型成员会调用这个成员类型的默认构造函数,如果没有则会报错。
class A
{
public:
A(int a)
:_a(a)
{}
private:
int _a;
};
class B
{
public:
B(int a, int ref)
:_aobj(a)
, _ref(ref)
, _n(10)
{}
private:
A _aobj; // 没有默认构造函数
int& _ref; //引用
const int _n; // const
};
这里是类A没有默认构造函数,所以需要在类B那里初始化,在初始化_aobj(a)时会调用类A的构造函数,执行类A的构造函数会先执行类A的初始化列表在会去执行类A构造函数的内容,所有的构造函数都会执行其的初始化列表。
尽量使用初始化列表初始化,因为不管是否使用初始化列表,对于自定义类型成员变量,一定会先使用初始化列表初始化。
class Time
{
public:
Time(int hour = 0)
:_hour(hour)
{
cout << "Time()" << endl;
}
private:
int _hour;
};
class Date
{
public:
Date(int day)
{}
private:
int _day;
Time _t;
};
int main()
{
Date d(1);
}
虽然类Date没有写初始化列表,但是还是会走,有走没有也走,然后就会到类Time的构造函数处走类Time的初始化列表去初始化_t
1.2成员变量在类中声明次序就是其初始化列表的初始化顺序,与其在初始化列表的先后顺序次序无关
声明的顺序是内存存放的顺序。
class A
{
public:
A(int a)
:_a1(a)
,_a2(_a1)
{}
void Print() {
cout<<_a1<<" "<<_a2<<endl;
}
private:
int _a2;
int _a1;
};
int main() {
A aa(1);
aa.Print();
}
A. 输出1 1
B.程序崩溃
C.编译不通过
D.输出1 随机值
类A是先声明 _a2在声明_a1,所以初始化列表也是先初始化_a2在_a1,但是初始化_a2时_a1的值是为初始化的,所以是一个随机值,而_a1则是1
声明(Declaration)
- 目的:声明用于告诉编译器某个变量、函数或类的存在,并且指定其类型或签名,但不分配内存或实现其功能。
- 作用:声明让编译器知道某个标识符的名字和类型,以便在其他地方使用该标识符。声明不提供实际的内存分配或具体的实现细节。
定义(Definition)
- 目的:定义用于实际创建变量、实现函数或类,并为其分配内存或提供具体的实现细节。
- 作用:定义不仅告诉编译器某个标识符的名字和类型,还实际分配内存并提供功能实现。每个变量、函数或类在程序中只能有一个定义。
2.static成员
2.1概念
声明static的类成员为类的静态成员,用static修饰的成员变量,为静态成员变量;用static修饰的成员函数为静态成员函数。静态成员变量一定要在类外进行初始化。
例子:
创建类A,有默认构造函数,拷贝构造函数和析构函数,都会改变_count的值,首先先打印_count的值,然后在创建俩个类A的变量,这时_count的值会加2,而后在{}里面拷贝构造一个a3又会加1,但是出了{}就会触发析构函数,因为局部变量出了{}就会销毁。
class A
{
public:
A()
{
++_count;
}
A(const A& t)
{
++_count;
}
~A()
{
--_count;
}
static int GetCount()
{
return _count;
}
private:
static int _count;
};
int A::_count = 0;
int main()
{
cout << A::GetCount() << endl;
A a1, a2;
{
A a3(a1);
cout << A::GetCount() << endl;
}
cout << A::GetCount() << endl;
return 0;
}
2.2特性
1.静态成员为所有类对象共享,不属于某个具体的对象,存放在静态区
2.静态成员变量必须在类外定义,定义时不添加static关键字,类中只是声明
3.类的静态成员可用类名::静态成员或者对象.静态成员来访问
4.静态成员没有隐藏的this指针,不能访问任何非静态成员
5.静态成员也是类的成员,受public,protected,private影响
3.友元类
友元类的所有成员函数都可以是另一个类的友元函数,都可以访问另一个类中的非公有成员
1.友元关系是单向的,不具有交换性。
比A是B的友元类,但B不是A的友元类,你把我当朋友,我不把你当朋友。
友元关系不能传递
class Time
{
friend class Date;
public:
Time(int hour=0,int minute=0,int second=0)
:_hour(hour)
,_minute(minute)
,_second(second)
{}
private:
int _hour;
int _minute;
int _second;
};
class Date
{
public:
Date(int year = 1900, int month = 1, int day = 1)
{
_year = year;
_month = month;
_day = day;
}
void Set(int hour, int minute, int second)
{
_t._hour = hour;
_t._minute = minute;
_t._second = second;
}
private:
int _year;
int _month;
int _day;
Time _t;
};
像下面代码,类A和B互为友元,但是会报错,因为类A写在前面是要在上面去找类B的,要前置声明才可以,所以把俩个类写在一起就比较方便。
class B;
class A
{
//友元声明
friend void func(const A& aa, const B& bb);
private:
int _a1 = 1;
int _a2 = 2;
};
class B
{
//友元声明
friend void func(const A& aa, const B& bb);
private:
int _b1 = 3;
int _b2 = 4;
};
可以在Date中访问类Time的非公开成员变量
例题:
这里的变长数组的作用是有多长就调用多少次类sum的构造函数,就可以实现累加。
class sum
{
public:
sum()
{
_ret += _i;
++_i;
}
static int GetRet()
{
return _ret;
}
private:
static int _i;
static int _ret;
};
int sum:: _i=1;
int sum::_ret = 0;
class Solution
{
public:
int sum_solution(int n)
{
sum a[n];
return sum::sum[n];
}
};
4.内部类
概念:如果一个类定义在另一个类的内部,这个类就叫内部类,内部类是一个独立类,它不属于外部类,不能通过外部类的对象去访问内部类的成员,外部类对内部类没有任何优越的访问权限。
注意:内部类就是外部类的友元,内部类可以访问外部类的成员,但是外部类不能访问内部类的成员。
特性:
1.内部类可以在外部类的任何地方
2.sizeof(外部类)=外部类,内部类不占用外部类的大小。
class A
{
private:
static int k;
int h;
public:
class B // B天生就是A的友元
{
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;
}
上面的例题可以使用内部类进行优化:
class Solution
{
public:
class sum
{
public:
sum()
{
_ret += _i;
++_i;
}
};
public:
int sum_solution(int n)
{
sum a[n];
return _ret;
}
private:
static int _i;
static int _ret;
};
5.匿名
匿名对象就像一次性水杯一样,只使用一次就丢掉了,
// 生命周期只在当前一行
A(); // 匿名对象
A(1);
6.sort函数
可以实现数组的排序
sort(数组名,数组名+元素个数)
int a[] = { 12,23,34,4345,323,123,12332,1 };
sort(a, a + 8);
for (int i = 0; i < 7; i++)
{
cout << a[i] << " ";
}
实现降序:
bool myfunction(int i, int j) { return (i > j); }
int main()
{
int a[] = { 12,23,34,4345,323,123,12332,1 };
sort(a, a + 8,myfunction);
for (int i = 0; i < 7; i++)
{
cout << a[i] << " ";
}
return 0
}
还可以使用其它方法:
int main()
{
int a[] = { 12,343,56,2342,67,343,121,1223,2321 };
greater<int>gt;
sort(a, a + 8, gt);
for (int i = 0; i < 7; i++)
{
cout << a[i] << " ";
}
return 0;
}
使用匿名对象:
int main()
{
int a[] = { 12,343,56,2342,67,343,121,1223,2321 };
//greater<int>gt;
sort(a, a + 8, greater<int>());
for (int i = 0; i < 7; i++)
{
cout << a[i] << " ";
}
return 0;
}
降序:
int main()
{
int a[] = { 12,343,56,2342,67,343,121,1223,2321 };
//greater<int>gt;
sort(a, a + 8, less<int>());
for (int i = 0; i < 7; i++)
{
cout << a[i] << " ";
}
return 0;
}