#include<iostream>
using namespace std;
class date
{
public:
private:
int _year;//声明
int _month;
int _day;
//const int x;//存在会报错
};
int main()
{
date d(2023, 2, 10);//定义
//const int a=0;
return 0;
}
#include<iostream>
using namespace std;
class date
{
public:
date()
:a(1)//使用初始化列表进行定义
,c(2)
{
}
private:
int a=2;//声明
int b=1;
int q;
};
int main()
{
date d;
return 0;
}
1.每个成员变量只能在初始化列表出现一次(初始化只能初始化一次) 2.类中包含 引用成员变量 const成员变量 自定义类型成员(没有默认构造函数) ,必须放在初始化列表位置进行初始化,(剩下的成员在初始化列表写不写都行,但是上述这三类就必须在列表写)
#include<iostream>
using namespace std;
class A
{
public:
//A() //不传参数为默认构造函数
// :_a(1)//如果自定义类型的构造函数为这个 就不用在初始化列表初始化
//{
//}
A(int d)
:_a(d)
{
}
private:
int _a;
};
class date
{
public:
date()
:a(2)
,b(1)
,c(a)
,aa(5)
{
}
private:
int a = 1;//内置类型int
const int b = 2;//const
int& c;//引用
A aa;//自定义类型并且没有默认构造函数
};
int main()
{
//a=2 b=1 c=2 aa._a=5
date d;
return 0;
}
3.成员变量在类中的声明次序就是在初始化列表中的初始化顺序,在初始化列表中的先后次序无关
class A
{
public:
A(int a)
:_a1(a) //1
, _a2(_a1)
//随机值
{}
void Print() {
cout << _a1 << " " << _a2 << endl;
}
private:
int _a2;
int _a1;
};
int main() {
A aa(1);
aa.Print();// 1随机值
}
由于是先声明 _a2,再声明_a1,所以在初始化列表中先调用_a2,由于刚开始_a1为随机值 ,所以_a2为随机值,再调用_a1,将a的值1传给_a1,所以_a1=1,最终是 1 随机值
#include<iostream>
using namespace std;
class A
{
public:
A(int n)//构造函数
:_a(n)
{
cout << "A(int n)" << endl;
}
A(A& d)//拷贝构造
{
cout << "A(A&d)" << endl;
}
private:
int _a;
};
int main()
{
A a(1);//构造函数 构造
A b = 1;//隐式类型转换 构造+拷贝构造->优化 构造
//int i = 1;
//double d = i;//隐式类型转换
return 0;
}
但是程序运行发现,只进行了两次构造,并没有拷贝构造, 说明C++对于自定义类型产生临时变量,编译器会做优化
#include<iostream>
using namespace std;
class A
{
public:
A(int n)
:_a(n)
{
cout << "A(int n)" << endl;
}
A(A& d)
{
cout << "A(A&d)" << endl;
}
private:
int _a;
};
int main()
{
//A& ret = 1;//错误
const A& ret = 1;
return 0;
}
#include<iostream>
using namespace std;
class A
{
public:
explicit A(int n)//构造
:_a(n)
{
cout << "A(int n)" << endl;
}
A(A& d)//拷贝构造
{
cout << "A(A&d)" << endl;
}
private:
int _a;
};
int main()
{
A a(1);//构造函数
A b = 1;//隐式类型转换 加入关键字explicit会报错
return 0;
}
#include<iostream>
using namespace std;
class A
{
public:
explicit A(int n,int a)
:_a(n)
,_b(a)
{
cout << "A(int n,int a)" << endl;
}
A(A& d)
{
cout << "A(A&d)" << endl;
}
private:
int _a;
int _b;
};
int main()
{
//多参数的构造函数
A a(1, 2);
A a = { 1,2 };//隐式类型转换 加入关键字explicit就会报错
return 0;
}
同样在多参数的构造函数中,使用关键字explicit也可以防止隐式类型转换的发生
为了在类外面使用类中私有的成员变量,友元提供了突破封装的方式,在类中加入 friend+函数定义 但是这样会增加耦合度,所以不建议多用
#include<iostream>
using namespace std;
class date
{
public:
date(int year, int month, int day)
{
_year = year;
_month = month;
_day = day;
}
void operator<<(ostream& out)
{
out << _year << "-" << _month <<"-"<< _day << endl;
}
private:
int _year;
int _month;
int _day;
};
int main()
{
date d1(2023, 2, 10);
//cout << d1; 我们想实现成的
d1 << cout; //实际在类中生成的
return 0;
}
在类中,左操作数作为隐藏的this指针,指针类型为date*, cout<<d1等价于cout.operator<<(d1),若为cout<<d1,就会将cout作为左操作数, cout是标准库std命名里面一个ostream类型的全局对象,与this指针类型不符,所以在类中只能写成 d1<<cout 虽然输出了日期,但是输出方式不是我们想要的结果,我们想要使用 cout<<d1
#include<iostream>
using namespace std;
class date
{
public:
friend void operator<<(ostream& out, date& d);//firend+函数定义 说明函数为类的友元函数
date(int year, int month, int day)
{
_year = year;
_month = month;
_day = day;
}
private:
int _year;
int _month;
int _day;
};
void operator<<(ostream& out, date&d)
{
out << d._year << "-" << d._month << "-" << d._day << endl;
}
int main()
{
date d1(2023, 2, 10);
cout << d1;
return 0;
}
所以设置在类外面,这样就会把两个操作数都传过来当参数,没有this指针的问题, 同时 在类中 friend+函数定义,说明该函数是date类的友元函数,该函数不受访问限定符的限制
#include<iostream>
using namespace std;
class date
{
public:
friend void operator>>(istream& in, date& d);
private:
int _year;
int _month;
int _day;
};
void operator>>(istream& in, date& d)
{
in >> d._year >> d._month >> d._day;
}
int main()
{
date d1;
cin >> d1;
return 0;
}
cin是标准库std命名里面一个istream类型的全局对象, 在类外面定义需要在date类中加入friend+函数定义,使函数成为类的友元函数,该函数不受访问限定符的限制
1.友元函数可以访问类的私有和保护成员,但是不是类的成员函数 2.友元函数不能用const修饰 3.友元函数可以在类的定义的任何地方声明,不受访问限定符限制
class Time
{
public:
friend class date;//日期类是时间类的友元
Time(int hours=0,int minute=0,int second=0)
{
_hour = hours;
_minute = minute;
_second = second;
}
private:
int _hour;
int _minute;
int _second;
};
class date
{
public:
date(int year=1, int month=1, int day=1)
{
_year = year;
_month = month;
_day = day;
}
void print(int hour,int minute,int second)
{
//直接调用时间类的私有成员变量
_t._hour = hour;
_t._minute = minute;
_t._second = second;
}
private:
int _year;
int _month;
int _day;
Time _t;
};
由于日期类是时间类的友元,相当于日期类是时间类的好朋友,所以在日期类中使用时间类的私有成员变量, 但是反之,时间类并不是日期类的好朋友,也就不能在时间类中调用日期类的私有成员变量
1.友元是单向的,不具有交换性 2.友元不能传递,如果C是B的友元,B是A的友元,不能说明C是A的友元
用static修饰的成员变量,称之为静态成员变量;用static修饰的成员函数,称之为静态成员函数。静态成员变量一定要在类外进行初始化(后面会解释)
#include<iostream>
using namespace std;
class A
{
public:
A(int a=0)
{
n++;
}
A(A& d)
{
n++;
}
static int getn()//静态成员函数没有this指针
{
return n;
}
private:
//不属于某个对象,属于所有对象,属于整个类
static int n;//静态成员变量声明
};
int A::n = 0;//静态成员变量定义
int main()
{
A a;//构造
A b;//构造
A c(a);//拷贝构造
A d(b);//拷贝构造
cout << A::getn() << endl;//4
return 0;
}
静态成员变量声明时可以有缺省值吗? 不可以,缺省值是在初始化列表处进行初始化,而初始化列表是初始化非静态成员(属于对象的成员),而static修饰的成员属于共有的
#include<iostream>
using namespace std;
class date
{
public:
date()
{
cout << "date()" << endl;
}
~date()
{
cout << "~date()" << endl;
}
void print()
{
cout << "print" << endl;
}
private:
int _year;
int _month;
int _day;
};
int main()
{
date();//匿名对象,生命周期只在第一行
date().print();
return 0;
}
匿名对象特点为不用取名字,由于它的生命周期只有这一行,在下一行会自动调用析构函数 同时可以不用创建对象来调用类中的函数,直接使用匿名对象.函数
#include<iostream>
using namespace std;
class date
{
public:
void print()
{
cout << "print" << endl;
}
int sum(int n)
{
return n;
}
private:
int _year;
int _month;
int _day;
};
class A
{
public:
A(int n)
{
}
};
A fun()
{
int n = 0;
cin >> n;
int ret = date().sum(n);
//A d=ret; //正常来说创建一个对象接收 ,在返回对象
//return d;
return A(ret);//直接返回匿名对象
}
int main()
{
date();//匿名对象,生命周期只在第一行
return 0;
}
如果在一个类定义在另一个类的内部,这个类就叫做内部类
#include<iostream>
using namespace std;
class A
{
private:
int n;
public:
class B
{
public:
void print()
{
}
private:
int b;
};
};
int main()
{
cout << sizeof(A) << endl;//4
A::B b;//必须通过A类,然后才能访问B类创建对象b
return 0;
}
当我们计算A类的大小时发现为4,说明只计算了A类自身私有的成员变量n,并没有算上内部类B的成员变量 说明内部类B跟A是独立的,受A的类域限制
class A
{
public:
class B//B是A的友元
{
public:
void print(A&d)
{
//在B类中可以调用A的私有成员变量
cout << d.n << endl;
}
private:
int b;
};
private:
int n;
};
int main()
{
cout << sizeof(A) << endl;//4
return 0;
}
class A
{
public:
A(int a = 0)
:_a(a)
{
cout << "A(int a)" << endl;
}
private:
int _a;
};
int main()
{
A aa=1;//构造函数+拷贝构造 优化为 构造
return 0;
}
单参数的构造函数,编译器把构造函数+拷贝构造优化为构造(上面的explicit关键字做出详细解释)
class A
{
public:
A(int a = 0)
:_a(a)
{
cout << "A(int a)" << endl;
}
private:
int _a;
};
void func(A a)
{
}
int main()
{
func(2);//构造+拷贝构造 优化-> 构造
return 0;
}
class A
{
public:
A(int a = 0)
:_a(a)
{
cout << "A(int a)" << endl;
}
private:
int _a;
};
void func2(const A& a)//必须使用const修饰,临时变量具有常性
{
}
int main()
{
func2(2);//无优化
return 0;
}
class 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;
}
private:
int _a;
};
A func3()
{
A a;//构造
return a;
//拷贝构造
}
int main()
{
func3();//构造+拷贝构造 无优化
return 0;
}
return a返回时,因为传值返回,所以会拷贝构造一个临时变量 不会优化,因为 A a与 return a不在一个表达式中
#include<iostream>
using namespace std;
class 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;
}
private:
int _a;
};
A func3()
{
A a;
return a;
}
int main()
{
A b=func3();
return 0;
}
两次拷贝构造属于一个连续的步骤,所以编译器进行了优化, 最终只进行了 一次构造、一次拷贝构造
class 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;
}
private:
int _a;
};
A func4()
{
return A();
}
int main()
{
A b=func4();//构造+拷贝构造+拷贝构造 优化成 构造
return 0;
}
因为整体都在一个表达式中,所以在构造匿名对象,拷贝构造生成一个临时变量,在用临时变量拷贝构造传给b这个过程中都会被编译器优化,构造+拷贝构造+拷贝构造 优化成 构造
class 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;
}
private:
int _a;
};
A func4()
{
A a;
return a;
}
int main()
{
A c = func4();//构造+拷贝构造+拷贝构造 优化->构造+拷贝构造
cout << "---------------" << endl;
A b;//构造
b = func4();//构造+拷贝构造+赋值 无优化
return 0;
}
横线上面直接用一个表达式调用函数,调用函数,A a 构造一次,return a,拷贝构造生成一个临时变量,再用临时变量拷贝构造b,由于 两次拷贝构造是连续步骤,所以优化成一次拷贝构造 即 构造+拷贝构造 而横线下面先是在主函数中 A b构造一次 ,调用func4函数, A a构造一次 ,return a拷贝构造生成一个临时变量,由于此时的b已经被定义雇过了,所以此时 属于将临时变量赋值给 b ,进行运算符重载 所以 无优化 即 构造+构造+拷贝构造+赋值