目录
初始化列表(对象的成员定义的位置,声明的顺序一定要跟定义的顺序保持一致)
在声明的时候,给成员变量缺省值比较方便
指针和引用都涉及到权限
权限可以缩小,可以平移,但是不能放大
取地址运算符重载
不写编译器也会自动生成
只有一种场景下需要我们自己写
不希望别人取到地址
默认成员函数都不能重载成全局,编译器会默认生成一个,导致歧义
类和对象(下)
构造函数初始化两种方式
构造函数体赋值
初始化列表(对象的成员定义的位置,声明的顺序一定要跟定义的顺序保持一致)
初始化列表是构造函数的一部分
它替代的是函数体内赋值
我们不写每一个成员变量也会走初始化列表、
声明的顺序一定要跟定义的顺序保持一致
成员变量最多会走一次初始化列表,也最少会走一次初始化列表,有且只能出现一次
三种必须在初始化列表
引用,const,没有默认构造函数
引用与const的特征:必须在定义的时候初始化
#include<iostream>
using namespace std;
class A
{
public:
//默认生成构造函数,内置类型不做处理,自定义类型调用它的默认构造函数
A(int a,double b)
:_a(a)
,_b(b)
{
cout <<"A(int a = 0)"<< endl;
}
private:
int _a;
double _b;
};
class B
{
public:
//初始化列表:对象的成员定义的位置
//1.B(int a=1,int ref=1)
//2.
B(int a=1,int ref&=1)
:_n(a)
,_ref(ref)//按1走,ref是局部变量,这里会有野引用问题发生
//所以这里需要像2传引用
,aobj(3,3.14)//没有默认构造时
{
/*_n = 0;
_ref = ref;*/
}
private:
//声明
A aobj;//没有默认构造函数:A(int a ,double b)
//默认构造:编译器默认生成,全缺省,无参
//引用与const的特征:必须在定义的时候初始化
int& _ref;//引用
const int _n;//const
int _x=1;//这里1是缺省值,缺省值是给初始化列表的
};
int main()
{
int n=1;
int m=2;
//对象整体定义
//B bb1(10, 1);
B bb1(10, n);
//B bb2(11, 2);
B bb2(11, m);
return 0;
}
在初始化列表时,内置类型会走初始化列表,但如果没传值,就不做处理,自定义类型会去调用它的默认构造函数
为什么有初始化列表,还要有函数体内赋值?
因为有一些工作是初始化列表做不了的
例如:在初始化列表就无法检查开辟空间
动态开辟二维数组
初始化列表是有顺序的
初始化列表有顺序,按照声明顺序进行初始化,声明顺序跟定义顺序保持一致
容易写成这种问题
程序崩溃
野指针,内存越界
先走初始化列表,在走赋值
隐式类型转换
//隐式类型转换
class A
{
public:
//构造函数
A(int a=1)
: _a(a)
{
cout << "A(int a)" << endl;
}
//拷贝构造
A( const A& aa)
:_a(aa._a)
{
cout << "A(const A& aa))" << endl;
}
private:
int _a=1;
};
int main()
{
A a(2);
A b = 2;
const A & c = 2;
return 0;
}
class string
{
public:
string(const char* str)
{}
};
class list
{
public:
void push_back(const string& str)
{}
};
int main()
{
string name1("张三");
string name2 = "张三";
list lt1;
//两种方法,意义一样,下面的是因为隐式类型转换
string name3("李四");
lt1.push_back(name3);
lt1.push_back("李四");
return 0;
}
explicit(拒绝发生隐式转换)
如果不想要转换发生可以在构造函数前加一个explicit
Static
全局变量的劣势:任何地方都可以随意改变。
在类里面写静态变量,相当于用类去封装全局变量
并且不能给缺省值,因为静态变量没有初始化列表,缺省值是给初始化列表的
静态成员变量(在类外面定义)
成员变量—— 每一个对象都自己的成员变量,存储在对象里面
静态成员变量——属于类,属于类的每个对象共享,存储在静态区(它的生命周期是全局的)
不能在初始化列表中初始化,因为它不属于某个对象
可以通过公有的成员函数,访问私有变量
void Getdataname()
cout<<dataname<<endl;
静态成员函数
没有this指针,指定类域(类的名字)和访问限定符(::)就可以访问
#include<iostream>
using namespace std;
//计算还有多少个对象存在
class A
{
public:
A()
{
_count++;
}
~A()
{
_count--;
}
//静态成员函数没有this指针
//两种不同书写方式,打印方法也不同
/*static void Get_count()
{
cout << A::_count << endl;
}*/
//A::Get_count();
static int Get_count()
{
return _count;
}
//cout << __LINE__<<":" << A::Get_count () << endl;
private:
static int _count;
};
//全局位置,类外面定义
int A::_count = 0;
A aa;
void func()
{
//静态变量只能定义一次
static A aa1;
/*cout << __LINE__ <<":"<<aa1.Get_count() << endl;*/
A::Get_count();
}
int main()
{
/*A::Get_count();*/
cout << __LINE__<<":" << A::Get_count () << endl;
A aa1;
func();
func();
}
(非静态成员函数和非静态成员变量)与静态成员函数的关系
非静态能否调用静态:可以
静态能否调用非静态:不可以。非静态的成员函数调用需要this指针,没有this指针
//class A
//{
//public:
// A()
// {
// ++_scount;
// }
//
// A(const A& t)
// {
// ++_scount;
// }
//
// ~A()
// {
// --_scount;
// }
//
//
// void Func1()
// {
// // 非静态能否调用静态:可以
// GetACount();
// }
//
// void Func2()
// {
// ++_a1;
// }
//
// // 没有this指针,指定类域和访问限定符就可以访问
// static int GetACount()
// {
// // 静态能否调用非静态:不可以。非静态的成员函数调用需要this指针,我没有this
// // Func2();
//
// //_a1++;
// return _scount;
// }
//private:
// // 成员变量 -- 属于每个一个类对象,存储对象里面
// int _a1 = 1;
// int _a2 = 2;
public:
// // 静态成员变量 -- 属于类,属于类的每个对象共享,存储在静态区
// static int _scount;
//};
设计一个类只能在栈或堆上创建对象
class A
{
public:
static A GetStackObj()
{
A aa;
return aa;
}
static A* GetHeapObj()
{
return new A;
}
private:
A()
{}
private:
int _a1 = 1;
int _a2 = 2;
};
int main()
{
//static A aa1; // 静态区
//A aa2; // 栈
//A* ptr = new A; // 堆
A::GetStackObj();
A::GetHeapObj();
return 0;
}
访问限度符限度的是成员访问方式:成员变量,成员函数
友元
友元是一个声明,可以在类中任意位置
友元函数
耦合度太高,牵一发而动全身
可以声明在任意位置
友元类
#include<iostream>
#include<string>
using namespace std;
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;
};
2023.5.10
内部类
内部类分为两种:公有的内部类与私有的内部类
但是它受访问限度符限制
内部类在类里面声明不占空间,定义才占空间
定位了一个B类就变成了12;
内部类是外部类的天生友元;、
内部类能够访问外部类的数据,但外部类不能访问内部类的信息
匿名对象(即用即销毁)
类名+(参数)
匿名对象具有常性
const A& ra = A(2);//const引用延长匿名对象的生命周期,生命周期在当前函数局部域,
//匿名对象
class A
{
public:
//构造函数
A(int a=1)
:_a(a)
{
cout << "A(int a)" << endl;
}
~A()
{
cout << "~A()" << endl;
}
private:
int _a=1;
};
class Solution
{
public:
Solution()
{
}
~Solution()
{
cout << "~Solution()" << endl;
}
int Sum_Solution(int n)
{
cout << "Sum_Solution" << endl;
return n;
}
};
int main()
{
A a(2);//有名对象--生命周期在当前函数局部域
//匿名对象即用即销毁
A(2);//匿名对象--生命周期在当前行
A();//可以理解成后面就没人用了,就直接销毁了
// A& ra = A(1);//匿名对象具有常性
const A& ra = A(2);//const引用延长匿名对象的生命周期,生命周期在当前函数局部域,
//可以理解为因为后面ra还会用这个匿名对象,所以没有销毁
//创建对象,调用函数
Solution b;
//有名对象不能这样写 Solution A(); 因为编译器不知道这是对象,还是函数声明
b.Sum_Solution(10);
//匿名对象调用函数,还是会先走构造函数,再进入调用的函数,必须加一个括号,
//有默认构造函数不要传参,没有的话正常传参
Solution().Sum_Solution(10);
//Solution::Sum_Solution(10);错误调用,没有this指针可以传递
return 0;
}