个人能网站建设,东莞寮步伟易达电子厂,萍乡做网站,网站建设seo优化公司目录 1. 再谈构造函数
1.1 构造函数体赋值 1.2 初始化列表
1.3 explicit 2. static成员
2.1 概念 3. 友元
3.1 友元函数
3.2 友元类
4. 内部类 5. 匿名对象
6. 拷贝对象时编译器做出的优化 1. 再谈构造函数
1.1 构造函数体赋值 class Date
{
public:Date(int year2024…目录 1. 再谈构造函数
1.1 构造函数体赋值 1.2 初始化列表
1.3 explicit 2. static成员
2.1 概念 3. 友元
3.1 友元函数
3.2 友元类
4. 内部类 5. 匿名对象
6. 拷贝对象时编译器做出的优化 1. 再谈构造函数
1.1 构造函数体赋值 class Date
{
public:Date(int year2024, int month3, int day16){_year year;_month month;_day day;}void pri() {cout _year _month _day endl;}
private:int _year;int _month;int _day;
};
int main() {Date a;Date b(111);a.pri();b.pri();return 0;
} 虽然上述构造函数调用之后对象中已经有了一个初始值但是不能将其称为对对象中成员变量的初始化构造函数体中的语句只能将其称为赋初值而不能称作初始化。因为初始化只能初始化一次而构造函数体内可以多次赋值。 1.2 初始化列表 class Date
{
public:Date(int year, int month, int day)//初始化列表: _year(year), _month(month), _day(day){}void pri() {cout _year _month _day endl;}
private:int _year;int _month;int _day;
};
int main() {Date a(1,2,3);a.pri();return 0;
}初始化列表是每个成员变量定义初始化的位置 每个成员变量在初始化列表中只能出现一次(初始化只能初始化一次)const成员变量无法在函数体初始化得在初始化列表初始化 int ref;引用也得在初始化列表因为引用定义必须初始化 自定义类型成员(且该类没有默认构造函数时)也在初始化列表 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();
} 最后输出 1 -858993460 因为先初始化a2因为a2先在类中声明而且用的是a1的值初始化而a1是随机值 a1最后初始化为a是1 能用初始化列表就用初始化列表 成员变量的顺序与初始化列表的顺序最好一致因为成员变量在类中声明次序就是其在初始化列表中的初始化顺序与其在初始化列表中的先后 次序无关 1.3 explicit
单参数类型 class A {
public:A(int a0) :_aa(a){cout _aa endl;}private:int _aa;
};
class B {
private:int _a;int* p nullptr;int* pp (int*)malloc(4);
};
int main() {B bb;A c1(1);A c2 2;//单参数构造函数支持隐式类型转换//所以是2构造一个临时对象然后拷贝构造const A c3 4;return 0;
} 缺省值可以是其他的变量不局限于常量 如果不想存在隐式类型转换的话可以加explicit在构造函数前面 c2和c3就出错了 多参数类型 class A {
public:A(int a0,int b1) :_aa(a),_bb(b){cout _aa ;cout _bb endl;}private:int _aa;int _bb;
};
class B {
private:int _a;int* p nullptr;int* pp (int*)malloc(4);
};
int main() {B bb;A c1(1,2);A c2 {3,4};const A c3 {5,6};return 0;
} 多参数支持花括号产生隐式类型转换 同样加了explicit就不行了 用explicit修饰构造函数将会禁止构造函数的隐式转换 2. static成员
2.1 概念 声明为static的类成员称为类的静态成员用static修饰的成员变量称之为静态成员变量用 static修饰的成员函数称之为静态成员函数。静态成员变量一定要在类外进行初始化 静态成员函数没有this指针所以他只是为了访问静态成员变量他访问不了非静态成员变量因为没this class A
{
public:A() {n;}A(const A aa) {n;}
//private:static int n;//声明//属于整个类但本质还是静态全局变量
};
int A::n 0;//在类外定义
void func() {n 1;//那么这里就访问不了n了
}
int main() {A a;A b;cout n endl;//这里也是访问不了nreturn 0;} class A
{public:A() { _scount; }A(const A t) { _scount; }~A() { --_scount; }static int GetACount() { return _scount; }private:static int _scount;};int A::_scount 0;void TestA(){cout A::GetACount() endl;A a1, a2;A a3(a1);cout A::GetACount() endl;}int main() {TestA();return 0;} 最终结果0 3 当创建对象 a1 时会调用默认构造函数 A() 输出 _scount 的初始值初始值为 0。 创建对象 a1_scount 自增为 1。 创建对象 a2_scount 再次自增为 2。 通过复制构造函数创建对象 a3_scount 再次自增为 3。 输出 _scount 的最终值值为 3。 注意 1. 静态成员为所有类对象所共享不属于某个具体的对象存放在静态区 2. 静态成员变量必须在类外定义定义时不添加static关键字类中只是声明 3. 类静态成员即可用 类名::静态成员 或者 对象.静态成员 来访问 4. 静态成员函数没有隐藏的this指针不能访问任何非静态成员 5. 静态成员也是类的成员受public、protected、private 访问限定符的限制 3. 友元
友元提供了一种突破封装的方式有时提供了便利。但是友元破坏了封装所以友元不宜多用-慎用
3.1 友元函数 友元函数可以直接访问类的私有成员它是定义在类外部的普通函数不属于任何类但需要在类的内部声明声明时需要加friend关键字。 class Date
{//友元函数friend ostream operator(ostream out, const Date d);friend istream operator(istream in, Date d);public:Date(int year 1900, int month 1, int day 1):_year(year),_month(month),_day(day){}
private:int _year;int _month;int _day;
};ostream operator(ostream out, const Date d)
{out d._year / d._month / d._day endl;return out;
}
istream operator(istream in, Date d)
{in d._year d._month d._day;return in;
}
int main()
{Date d1;cin d1;cout d1;return 0;
} 友元函数是普通的全局函数 #include iostreamusing namespace std;class A
{private:int A;public:print(){};//声明全局函数 person 是 类A 的友元函数friend void person (int x);
}void person(int x)
{//使用了类A的成员变量agecout age p.age endl;}int main ()
{A p(22);person(p);return 0;
} 友元函数是其他类的成员函数 #include iostreamusing namespace std;class A
{private:int A;public:print(){};//声明类B的成员函数 person 是 类A 的友元函数friend void B::person (int x);
}class B
{private:int B;public:person(int x);}B::person(int x)
{//因为类B的成员函数person是类A的友元函数所以看可以使用类A的成员变量agecout age p.age endl;}int main ()
{A p(22);B q;q.person(p);return 0;} 注意 友元函数可访问类的私有和保护成员但不是类的成员函数友元函数不能用const修饰友元函数可以在类定义的任何地方声明不受类访问限定符限制一个函数可以是多个类的友元函数友元函数的调用与普通函数的调用原理相同 3.2 友元类 友元类的所有成员函数都可以是另一个类的友元函数都可以访问另一个类中的非公有成员。 友元关系是单向的不具有交换性。 比如上述Time类和Date类在Time类中声明Date类为其友元类那么可以在Date类中直接 访问Time类的私有成员变量但想在Time类中访问Date类中私有的成员变量则不行。 友元关系不能传递如果C是B的友元 B是A的友元则不能说明C时A的友元。 友元关系不能继承后续解析
//时间类
class Time
{friend class Date;
// 声明日期类为时间类的友元类则在日期类中就直接访问Time类中的私有成员变量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 SetTimeOfDate(int hour, int minute, int second){// 直接访问时间类私有的成员变量因为日期类是时间类的友元类_t._hour hour;_t._minute minute;_t._second second;}private:int _year;int _month;int _day;Time _t;
};
优缺点总结
缺点友元函数不是类的成员但是却具有成员的权限可以访问类中受保护的成员这破坏了类的封装特性和权限管控
优点可以实现类之间的数据共享比如上面互为友元类则可以互相访问对方受保护的成员
总结友元函数是一种破坏封装特性的机制可以让程序员写代码更灵活但是不能滥用
4. 内部类 概念如果一个类定义在另一个类的内部这个内部类就叫做内部类。内部类是一个独立的类它不属于外部类更不能通过外部类的对象去访问内部类的成员。外部类对内部类没有任何优越的访问权限。 注意内部类就是外部类的友元类内部类可以通过外部类的对象参数来访问外部类中的所有成员。但是外部类不是内部类的友元。 特性 1. 内部类可以定义在外部类的public、protected、private都是可以的。2. 注意内部类可以直接访问外部类中的static成员不需要外部类的对象/类名。3. sizeof(外部类)外部类和内部类没有任何关系。 // 1、B类受A类域和访问限定符的限制其实他们是两个独立的类
// 2、内部类默认就是外部类的友元类
class A
{//外部类不能访问内部类
public:class B // B天生就是A的友元{public:void print(const A a){cout k endl; //可以直接访问A的静态成员变量cout a.h endl; //也可以访问A的成员变量}};
private:static int k;int h;
};
int A::k 1;int main()
{A::B b;b.print(A());cout sizeof(A) endl; //8 外部类的大小与内部类无关 a与b相互独立的只不过b受a类的局域限制return 0;
}
类本身不占用空间 C不太喜欢使用内部类所以了解即可 5. 匿名对象
匿名对象的特点就是不用取名字生命周期只存在定义的这一行。
class A
{
public:A(int a 0):_a(a){cout A(int a) endl;}~A(){cout ~A() endl;}
private:int _a;
};int main()
{A aa1;//A aa1();// 不能这么定义对象因为编译器无法识别下面是一个函数声明还是对象定义// 但是我们可以这么定义匿名对象匿名对象的特点不用取名字A();// 但是他的生命周期只有这一行紧接着它的下一步就会自动调用析构函数A aa2(2);return 0;
} 应用场景 当我们做C的OJ题时会发现都是将其封装在一个Solution类中的假设我们需要调用这个类中的某一个函数是需要先创建一个Solution的对象然后通过这个对象进行调用这样的话有点麻烦我们可以直接使用匿名对象来调用这个类中的成员函数。
class Solution {
public:int Sum_Solution(int n) {//...return n;}
};
int main()
{// 1.基本方法Solution sl;sl.Sum_Solution(10);// 2.匿名对象Solution().Sum_Solution(10);return 0;
} 6. 拷贝对象时编译器做出的优化 在传参和传返回值的过程中一般编译器会做一些优化减少对象的拷贝这个在一些场景下还是非常有用的 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;}~A(){cout ~A() endl;}
private:int _a;
};
void f1(A aa)
{}
A f2()
{A aa;return aa;
}
int main()
{// 传值传参A aa1;f1(aa1);cout endl;// 传值返回f2();cout endl;// 隐式类型连续构造拷贝构造-优化为直接构造f1(1);// 一个表达式中连续构造拷贝构造-优化为一个构造f1(A(2));cout endl;// 一个表达式中连续拷贝构造拷贝构造-优化一个拷贝构造A aa2 f2();cout endl;// 一个表达式中连续拷贝构造赋值重载-无法优化aa1 f2();cout endl;return 0;
}