class Date
{
public:
Date(int year, int month, int day)
:_year(year)
,_month(month)
,_day(day)
{}
private:
int _year;
int _month;
int _day;
};
typedef int DataType;
class Stack
{
private:
int* _array;
int _capacity;
int _size;
public:
Stack(int capacity)//这里需要传参,不是默认构造函数
{
_array = (DataType*)malloc(sizeof(DataType) * capacity);
if (_array == NULL)
{
perror("_array malloc fail");
return;
}
_capacity = capacity;
_size = 0;
}
void Push(DataType data)
{
if (_capacity == _size)
{
int newcapacity = 2 * _capacity;
DataType* p = (DataType*)realloc(_array, newcapacity * sizeof(DataType));
_capacity = newcapacity;
_array = p;
}
_array[_size] = data;
_size++;
}
};
class MyQueue
{
private:
Stack _pushst;
Stack _popst;
int _size;
const int _n;
int& _ref;
int* _ptr;
public:
MyQueue(int n, int& rr)
: _pushst(n)//显示调用Stack的构造函数,初始化_pushst
, _popst(n)
, _size(0)
, _n(10)
, _ref(rr)
,_ptr((int*)malloc(40))
{
memset(_ptr, 1, 40);//这里要先给空间,在初始化空间中的值设置为1,此时初始化列表不能全部完成,需要借助函数体才能实现
}
};
int main()
{
int xx = 0;
MyQueue q1(10, xx);
return 0;
}
在上述程序中
规则:按成员声明顺序初始化(与初始化列表顺序无关),初始化顺序尽量和声明顺序一致。
class A
{
public:
A(int a)
:_a1(a)
,_a2(_a1)
{}
void Print() {
cout<<_a1<<" "<<_a2<
上述程序的输出为 “1 随机值”,因为先声明a2再声明a1,在初始化列表中a2先初始化=》a2(a1) = 随机值, a1再初始化a1(a)==a1(1)==1.
对于自定义类型成员变量,会先使用初始化列表初始化:初始化列表无论写不写,每个成员变量都会默认在初始化列表上走一遍,此时,自定义类型在这调用自己的默认构造函数(没有默认构造函数汇报错),内置类型有缺省值就调用,没有就取决于编译器是否处理。
class A
{
public:
// 单参数构造函数
//explicit A(int a)
A(int a)
:_a(a)
{
cout << "A(int a)" << endl;
}
// 多参数构造函数
A(int a1, int a2)
:_a(0)
,_a1(a1)
,_a2(a2)
{cout << "A(int a1, int a1)" << endl;}
A(const A& aa)
:_a(aa._a)
{
cout << "A(const A& aa)" << endl;
}
private:
int _a;
int _a1;
int _a2;
};
int main()
{
A aa1(1);//输出A(int a)
// 拷贝构造
A aa2 = aa1;//输出A(const A& aa)
// 隐式类型转换:内置类型转换为自定义类型
// 3构造一个A的临时对象,在用这个临时对象拷贝构造aa3,
//编译器遇到连续构造+拷贝构造->优化为直接构造
A aa3 = 3;//这里优化为直接构造,输出A(int a)
// raa 引用的是类型转换中用3构造的临时对象
const A& raa = 3;//因为临时对象具有常性,需要在引用前加const作修饰
//多参数
A aaa1(1, 2);
A aaa2 = { 1, 2 };
const A& aaa3 = { 1, 2 };
return 0;
}
在A aa3 = 3;中,语法上,3会首先构造一个A的临时对象(A(int a)),再将这个临时对象拷贝构造aa3(A(const A& aa)),但当编译器遇到构造+拷贝构造时,会优化为直接构造(A(int a))。
const A& raa = 3;中,3构造一个临时对象,临时对象具有常性,引用时需要添加const修饰。
类型转换若不产生临时对象,则内置类型3不能直接构造自定义类型A。因为A支持用int去构造,所以可以用int类型去构造,同时3是内置类型,不能直接去构造自定义类型,所以需要用3去构造一个临时的自定义类型,再用这个临时的自定义类型去拷贝构造。
是由单参数构造函数支持的,多参数不支持。
特性与使用场景
class A {
public:
A() { ++_scount; }
static int GetCount() { return _scount; }
private:
static int _scount; // 声明
};
int A::_scount = 0;
友元提供了一种突破封装的方式,有时提供便利,但会增加耦合度,破坏封装,不易多用。
分类:友元函数、友元对象
可以直接访问类的私有成员,它是定义在类外部的普通函数,不属于任何类,但需要在类内部声明,声明时需要加friend关键字.
friend ostream& operator<<(ostream& _cout, const Date& d);
特性:
友元类的所有成员函数都可以是另一个类的友元函数,都可以访问另一个类中的非公有成员。
特性:
Date
是Time
的友元类 → Date
可访问Time
私有成员,反之不可在传参和传返回值的过程中,一般编译器会做一些优化,减少对象的拷贝。
类:
class A
{
private:
int _a;
public:
A(int a = 0)
:_a(a)
{
cout << "A(int a)" << endl;
}
A(const A& aa)
:_a(aa._a)
{
cout << "A(const A& aa)" << endl;
}
A& operator=(const A& aa)
{
cout << "A& operator = (const A& aa)" << endl;
if (this != &aa)
{
_a = aa._a;
}
return *this;
}
~A()
{
cout << "~A()" << endl;
}
};
void f1(A aa)//2.自定义类型传参,A aa(aa1),调用拷贝构造,用aa1初始化aa,输出"A(const A& aa)"
{}//3.结束时,aa销毁,自动调用析构,输出"~A()"
int main()
{
//传值传参
A aa1;//1.生成时自动调用默认构造,输出"A(int a)"
f1(aa1);//4.函数结束时调用析构,输出"~A()"
}
A f2()
{
A aa;//1.构造
return aa;//2.传值返回,拷贝构造
}//3.析构
int main()
{
A ret = f2();//4.拷贝构造ret
return 0;//5.析构
}
A f2()
{
A aa;//构造
return aa;//传值返回,拷贝构造
}
void f1(A aa)//临时对象拷贝,调用拷贝构造
{}
int main()
{
f1(1);//A支持用int行构造,所以用1先构造一个临时对象,调用构造。构造+拷贝构造
f1(A(2));//A(2)构造一个对象,再拷贝给aa,构造+拷贝构造
A aa1;
aa1 = f2();//拷贝构造+赋值
return 0;
}