欢迎光临
我们一直在努力

类和对象进阶:初始化列表的标准使用、隐式类型转换、static成员、友元型的使用、匿名对象、及小点:内部类与对象拷贝时的编译器优化

目录

※一、初始化列表

※初始化列表使用总结:

构造-析构顺序练习题:

二、类与对象中的隐式类型转换

三、static修饰类成员

四、友元类、友元函数

五、匿名对象

六、较少应用知识点

内部类

对象拷贝时的编译器优化


    前言:在了解了类和对象的基本内容之后就可以深入了解一些类与对象的拓展使用方法~

※一、初始化列表

前言:构造函数初始化的一种方法。集中实现变量、常量的初始化赋值 (秩序性、简洁性)。            标注:※为复习重点

格式:在构造函数的下一行(可在末尾)以" : "开头后接初始化目标名字后接"()"内部值决定初始化目标的值 最后加"{}" () 。  ()内部可以为:变量、计算式。示例:

class Date
{
public:
Date(int year, int month, int day)
:_year(year)
,_month(month)
,_day(day)
{
; // 此处可以不加;但是必须加{}!!
}
private:
int _year;
int _month;
int _day;
};

对于初始化列表有以下规定:(最后总结) ※1.const 对象  引用对象  没有默认构造的类类型变量 必须写入初始化列表。

class Date
{
public:
Date(int year, int month, int day, int& x)
:_year(year)
, _month(month)
, _day(day)

,_t(12)
,ref(x) //注意此处的引用必须要传入变量了
,_n(x)
{
; // 此处可以不加;但是必须加{}!!
}
private:
int _year;
int _month;
int _day;

Time _t; //没有默认构造
int& ref; //引用
const int _n;//const
};

2.尽量写入初始化列表 因为即使变量你没有写入它仍会走初始化列表(假如你在定义时就进行了初始化那么调用此缺省值 如下:)

class Date1
{
public:
Date1(int year, int month)
:_year(year)
, _month(month)
{
; //
}
private:
※private区域给予初始化 实际时缺省值在进行初始化列表时假如没有 那么调用此缺省值
int _year = 2007;
int _month = 1;
int _day = 28; //自动缺省初始化为28
};

3.初始化列表的初始化顺序是按照声明顺序执行的而非按照初始化列表中的顺序。

    推荐的构造函数初始化的基本格式:

class Date1
{
public:
Date1(int year = 2007, int month = 1, int day = 28)
:_year(year)
,_month(month)
,_day(day)
{ }
void Print() const
{
cout << _year << "/" << _month << "/" << _day << endl;
return;
}
private:
int _year;
int _month;
int _day;
};

※初始化列表使用总结:

1.const 对象  引用对象  没有默认构造的类类型变量 必须写入初始化列表。 2.尽量写入初始化列表 因为即使变量你没有写入它仍会走初始化列表(假如你在定义时就进行了初始化那么调用此缺省值 如下:) 3.初始化列表的初始化顺序是按照声明顺序执行的而非按照初始化列表中的顺序。

构造-析构顺序练习题:

下⾯程序的运⾏结果是什么()

A. 输出 1 1

B. 输出 2 2

C. 编译报错

D. 输出 1 随机值

E. 输出 1 2

F. 输出 2 1

#include<iostream>
using namespace std;
class A
{
public:
A(int a)
:_a1(a)
, _a2(_a1)
{}
void Print()
{
cout << _a1 << " " << _a2 << endl;
}
private:
int _a2 = 2;
int _a1 = 2;
};
int main()
{
A aa(1);
aa.Print();
}

                                                                                                               答案:D 原因分析:(按照声明顺序读代码) 1.先进入主函数—类的初始化。 2.由于先是_a2声明先初始化_a2初始化为_a1但是此时_a1未初始化是随机值。 3._a1初始化为主函数传入的"1"。

二、类与对象中的隐式类型转换

功能:方便构造 

1.内置类型转为类类型对象,需要有相关内置类型为参数的构造函数。 2.在构造函数前+explicit [ɪkˈsplɪsɪt] (清晰的) 表示此构造函数不再支持隐式类型转换。 3.类类型的对象之间也可以隐式转换,需要相应的构造函数支持。(实用价值少……文章不涉及~)

#include <iostream>
using namespace std;

class Date
{
public:
// 单参数构造函数 – 允许隐式转换
Date(int year)
: _year(year)
, _month(1)
, _day(1)
{
cout << "Date(int) 构造: " << year << endl;
}

void print() const
{
cout << _year << "-" << _month << "-" << _day << endl;
}
private:
int _year;
int _month;
int _day;
};

void func(Date d) {
d.print();
}

int main() {
// 隐式类型转换发生的地方

// 初始化时
Date d1 = 2024; // ✅ 隐式转换:int → Date
d1.print();

return 0;
}

若隐式转换中传入多个参数其格式有: Date d1; d1 = {2009, 9, 1};

三、static修饰类成员

前言:static加上后表示静态性质——存储于内存的静态区,不因在类内而隶属于某一对象。                                                                                      ↓                                                                         为所有对象所共享(都可访问)

1.静态成员变量一定要在类外初始化。 2.静态函数没有this指针。 3.静态成员受类内访问限定符限制(private pritected public)。 4.由于静态成员在类内 所以规定访问必须指定如:Date::valuable。 5.静态成员变量不能在声明位置给初始值进行初始化 静态成员不属于任意对象 不走初始化列表初始化。

四、友元类、友元函数

1.友元提供了一种突破类访问限定符的封装方式,友元分为友元函数与友元类,在函数声明或类声明前加friend,并且把友元声明放到一个类的里面。 2.外部友元函数可以访问类的的私有和保护成员,友元函数仅仅是一种声明他表示类的成员函数。 3.友元函数可以在类的任何地方声明因为其的使用不受类访问限定符的限制。 4.一个函数可以是多个类的友元函数(不推荐使用)。 5.友元类中的成员函数都可以是另一个类的友元函数,都可以定位另一个类中的私有和保护成员。 6.友元关系是单向的不具有交换性,即在A类中声明友元类B,那么B类可以访问A类中的私有成员。但是A类不能访问B类的私有成员。代码如下: 7.友元关系不能传递,如A是B的友元B是C的友元,但是A不是C的友元。 8.友元会增加耦合度,破坏了封装,所以友元不宜多用。

//友元的单向性
class Date1;

class Date
{
friend class Date1;
//Date2类中定义友元类Date——Date2类的友元类是Date——Date2中可以访问Date中的数据
public:
//void Print(Date1 d)
//{
// cout << d.m << endl; //err 不能访问d.m 友元类 单向性的体现
//}
int n = 0;
};

class Date1
{
public:
void Print(Date d)
{
cout << d.n << endl; //可以访问d.n
}
int m = 0;
private:
static int max; //类内声明
};

五、匿名对象

1.使用类型(实参)定义出来的对象叫做匿名对象,我们之前定义的"类型 名称"叫做有名对象。 2.匿名对象的生命周期只在当前这一行,这一行结束就会析构。

//匿名对象

class Date
{
public:
Date(int a = 1)
{
int _a = a;
}
void Print(const Date& d) const //只读成员函数
{
cout << d._year << endl; //err 为什么不可以访问? 生命周期!
}
private:
int _year;
int _month;
int _day;
};

int main4()
{
//例一.
Date(); //匿名对象
Date(2); //匿名对象
//例二.
Date d1;
Date().Print(d1); //使用匿名对象节省了空间

return 0;
}

六、较少应用知识点

内部类

1.如果一个类定义在另一个类的内部,这个内部类就佳作内部类。内部类是一个独立的类跟定义在全局相比,它只是受外部类类域限制和访问限定符限制所以外部类定义的对象不包含内部类。 2.内部类默认是外部类的友元类。 3.内部类的本质也是一种封装,当A跟B类紧密相关,A类实现出来主要就是给B类使用,那么可以考虑把A类设计为B的内部类,如果放到private/protected位置,那么A类就是B类的专属内部类,其他地方都用不了。

对象拷贝时的编译器优化

1.现代编译器为尽可能地提高程序的效率,在不影响正确性的情况下会尽可能地减少一些传参和传值返回可以省略的拷贝。 2.如何优化 程度如何C++没有严格规定,取决于编译器。

赞(0)
未经允许不得转载:171主机测评 » 类和对象进阶:初始化列表的标准使用、隐式类型转换、static成员、友元型的使用、匿名对象、及小点:内部类与对象拷贝时的编译器优化
分享到: 更多 (0)

评论 抢沙发

  • 昵称 (必填)
  • 邮箱 (必填)
  • 网址