类和对象
# 1 概念
- class 封装的本质,在于将数据和行为,绑定在一起然后能过对象来完成操作。可以达到,对内开放数据,对外屏蔽数据,对外提供接口。
- struct和class关键字区别
- 在用struct定义类时,所有成员的默认属性为public,希望直接访问其内部数据使用struct
- 在用class定义类时,所有成员的默认属性为private,需要屏蔽内部数据,提供接口使用class
# 2 构造函数
主要完成数据初始化,在对象创建时自动调用构造函数。
# 2.1 初始化列表
当类成员中含有一个const对象时,或者是一个引用时,他们也必须要通过成员初始化列表进行初始化,因为这两种对象要在声明后马上初始化,而在构造函数中,做的是对他们的赋值,这样是不被允许的。
初始化列表中的初始化顺序,与声明顺序有关,与前后赋值顺序无关。
# 2.2 默认构造函数
A() = default;//使用默认构造函数
A() = delete; //禁止使用默认构造函数
A(const A&)=delete;//表示删除默认拷贝构造函数,即不能进行默认拷贝
A& operator=(const A&)=delete;//表示删除默认赋值函数
# 2.3 拷贝构造函数
由己存在的对象,创建新对象。也就是说新对象,不由构造器来构造,而是由拷贝构造器来完成。
提示
拷贝构造函数的应用场景
- 场景1
void test1()
{
Test t1(10, 20);
//⽤对象t1初始化对象t2
Test t2(t1); //也可写成Test t2 = t1; 等价
}
- 场景2
void func(Test t)//Test t = t1; //Test t 的拷贝构造函数
{
cout << "func begin..." << endl;
t.printT();
cout << "func end..." << endl;
}
- 场景3-匿名对象
Test func2()
{
cout << "func2 begin..." << endl;
Test temp(10, 20);
temp.printT();
cout << "func2 end..." << endl;
return temp;
}//返回的是匿名对象,匿名的对象=temp,调用匿名对象的拷贝构造函数
void test3()
{
cout << "test3 being.. " << endl;
func2();// 返回一个匿名对象。 当一个函数返回一个匿名对象的时候,函数外部没有任何变量去接收它,这个匿名对象将不会再被使用,(找不到),编译会直接将个这个匿名对象回收掉,而不是等待整个函数执行完毕再回收.
cout << "test3 end" << endl;
}
# 2.4 拷贝赋值运算符
需要分清赋值还是初始化
// 场景1
t3 = t1; //调用的不是t3拷贝构造函数,而是t3的赋值操作符函数
// 场景2
void test6()
{
cout << "test6 begin..." << endl;
Test t1;//t1已经被初始化了。
t1 = func2(); //t1已经被初始化了,所以func2返回的匿名对象不会再次转正,而依然是匿名对象。
//所以t1会调用等号操作符,t1.operator=(匿名对象), 然后编译器会立刻回收掉匿名对象
t1.printT();
cout << "test6 end.." << endl;
}
// 以上两种情况调用的是赋值操作
//=赋值操作符
void operator=(const Test &another)
{
m_x = another.m_x;
m_y = another.m_y;
}
结论
- 函数的返回值是⼀个元素(复杂类型的), 返回的是⼀个新的匿名对象(所以会调⽤匿名对象类的copy构造函数)
- 有关匿名对象的去和留
如果⽤匿名对象初始化另外⼀个同类型的对象,匿名对象转成有名对象
如果⽤匿名对象赋值给另外⼀个同类型的对象,匿名对象被析构
# 2.4 移动构造函数
右值引用资料:https://www.cnblogs.com/qicosmos/p/4283455.html
# 3 访问权限
注意
关于类成员函数中访问同类对象的私有成员,主要包含以下几种场景
- 在C++的类的成员函数中,允许直接访问该类的对象的私有成员变量。
- 在类的成员函数中可以访问同类型实例的私有变量。
- 拷贝构造函数里,可以直接访问另外一个同类对象(引用)的私有成员。
- 类的成员函数可以直接访问作为其参数的同类型对象的私有成员。
关于该问题(知识点)的讨论和或解释:
- 私有是为了实现“对外”的信息隐藏,或者说保护,在类自己内部,有必要禁止私有变量的直接访问吗?
- C++的访问修饰符的作用是以类为单位,而不是以对象为单位。
- 每个类的对象都有自己的存贮空间,用于存储内部变量和类成员;但同一个类的所有对象共享一组类方法,即每种方法只有一个源本。
- 访问权限是相对于类而言,而非对象!
# 4 静态成员变量和成员函数
# 4.1 静态成员变量
- static 成员变量实现了同类对象间信息共享。
- static 成员类外存储,求类大小,并不包含在内。
- static 成员是命名空间属于类的全局变量,存储在 data 区。
- static 成员只能类外初始化。
- 可以通过类名访问(无对象生成时亦可),也可以通过对象访问。
# 4.2 静态成员函数
- 静态成员函数的意义,不在于信息共享,数据沟通,而在于管理静态数据成员, 完成对静态数据成员的封装。
- 静态成员函数只能访问静态数据成员。原因:非静态成员函数,在调用时this 指针被当作参数传进。而静态成员函数属于类,而不属于对象,没有 this 指针。
C++类对象中的成员变量和成员函数是分开存储的
成员函数:存储于代码段中。
成员变量:
- 普通成员变量:存储于对象中,与struct变量有相同的内存布局和字节对齐方式
- 静态成员变量:存储于全局数据区中
# 5 const修饰的成员函数
# 5.1 const修饰成员函数
在成员函数的后边加上const
- const修饰成员函数时是修饰成员函数的this指针所指向的对象,也就是保证在调用这个const成员函数的对象时不会被改变。
- const对象可以调用const修饰的成员函数,不能调用非cosnt修饰的成员函数。
- 非const对象可以调用const修饰的成员函数,和非const修饰的成员函数
- 常成员函数的const和non-const版本同时存在时,const object只能调用const版本,non-const object只能调用non-const版本。 注意:
- const放在函数后边,该函数为只读函数,不允许修改其中的数据成员的值。
- const放在函数前面,修饰的是返回值,表示返回的是指针所指向值是常量,即表示返回值不可改变。
# 5.2 const修饰函数返回值
- 如果函数返回值采用“值传递方式”,由于函数会把返回值复制到外部临时的存储单元中,加const 修饰没有任何价值。
- 如果给以“指针传递”方式的函数返回值加const 修饰,那么函数返回值(即指针)的内容不能被修改,该返回值只能被赋给加const 修饰的同类型指针。
- 但是返回值不是内部数据类型,例如:A get_string(void),这样会产生一个临时的对象用来存放返回的数据,会调用拷贝构造函数,这样效率会低,所以采用“引用传递”A &get_string(void),如果加上const那么返回值的内容就不会被改变const A &get_string(void)。