2023-3-7首次编辑
目录:
Unit 4:类和对象
一.概念
类:
- 自定义数据类型(C语言的结构体进化而成)
对象:
- 类实例化出来的,用自定义数据类型定义的一个变量
#define _CRT_SECIRE_NO_WARNINGS
#include <iostream>
using namespace std;
//1.类
class Maker
{
public:
int a; //成员变量(成员属性)
void func() //成员函数(成员方法)
{
cout << "func" << endl;
}
};
int main()
{
Maker m; //2.对象
system("pause");
return 0;
}
二.类的封装
封装:
- 把 变量(属性) 和 函数(方法) 封装到类内
- 然后给这些数据赋予权限
目的:
- 防止乱调用函数和变量,出现错误
- 维护代码更方便
#define _CRT_SECIRE_NO_WARNINGS
#include <iostream>
#include "string"
using namespace std;
class Maker
{
public: //公有权限
void set(string Name, int Id)
{
id = Id;
name = Name;
}
void printMaker()
{
cout << "id=" << id << endl << "name=" << name << endl;
}
private: //私有权限
int id;
string name;
protected: //保护权限
int a;
};
void test()
{
Maker m;
m.set("小花", 1);
m.printMaker();
}
int main()
{
test();
system("pause");
return 0;
}
权限:
- 类外可以访问 公有权限 的成员
- 类外不能访问 私有/保护权限 的成员
- 类内没有权限之分
尽量把 变量(属性) 设置为 私有权限 :
- 可以控制 变量(属性) 的读写权限
- 可赋予客户端访问数据的一致性
- 可以保护 变量(属性) 的合法性
三.类和结构体的区别
- 结构体的默认权限 : 公有的
- 类的默认权限 : 私有的
四.初始化和清理的概念
- 当对象产生时,必须初始化成员变量
- 当对象销毁前,必须清理对象
- 初始化用构造函数
- 清理用析构函数
- 这两个函数时编译器调用
Unit 5:构造函数和析构函数
一.概念
#define _CRT_SECIRE_NO_WARNINGS
#include <iostream>
using namespace std;
//编译器默认提供默认的构造函数和析构函数
class Maker
{
public:
Maker()//默认的构造函数,函数体是空的
{
}
~Maker()//磨人的析构函数,函数体是空的
{
}
};
//A.构造函数的作用
class Maker1
{
public:
//初始化成员变量,是编译器去调用的
Maker1()
{
a = 10;
cout << "构造函数" << endl;
}
//析构函数:在对象销毁前,编译器调用析构函数
~Maker1()
{
cout << "析构函数" << endl;
}
public:
int a;
};
void test1()
{
Maker1 m1;
//实例化对象,内部做了两件事:
//1.分配空间
//2.调用构造函数进行初始化
int b = m1.a;
cout << b << endl;
}
//B.析构函数的作用
class Maker2
{
public:
//有参构造函数
Maker2(const char* name, int age)
{
cout << "有参构造" << endl;
//申请堆区空间
pName = (char*)malloc(strlen(name) + 1);
strcpy(pName, name);
mAge = age;
}
void printMaker2()
{
cout << "name:" << pName << endl;
cout << "age:" << mAge << endl;
}
~Maker2()
{
cout << "析构函数" << endl;
//释放堆区空间
if (pName != NULL)//防止脏数据
{
free(pName);
pName = NULL;
}
}
private:
char *pName;
int mAge;
};
void test2()
{
Maker2 m2("翠花", 18);
m2.printMaker2();
}
int main()
{
test1();
test2();
system("pause");
return 0;
}
注意:
- 构造函数和析构函数的权限必须是公有的
- 构造函数可以重载
- 构造函数没有返回值,不能用void,可以有参数
- 析构函数没有返回值,不能用void,没有参数
- 先构造的函数,后析构
- 有对象产生必然会调用构造函数
- 有对象销毁必然会调用析构函数
- 有多少个对象产生就会调用多少次构造函数
- 有多少个对象销毁就会调用多少次析构函数
二.拷贝构造函数
#define _CRT_SECIRE_NO_WARNINGS
#include <iostream>
using namespace std;
class Maker1
{
public:
Maker1()
{
cout << "无参构造函数" << endl;
a = 20;
}
//拷贝构造函数
Maker1(const Maker1 &m)//形参要用引用
{
cout << "拷贝构造函数" << endl;
a = m.a;
}
void printMaker1()
{
cout << "a=" << a << endl;
}
private:
int a;
};
void test1()
{
Maker1 m1;
m1.printMaker1();
//用一个已有的对象去初始化另一个对象
Maker1 m2(m1);//调用拷贝构造函数
//如果拷贝构造函数中的形参不是引用
/*
Maker1(const Maker1 m) →const Maker1 m = m1;→const Maker1 m(m1);
{
cout << "拷贝构造函数" << endl;
}
1.Maker1 m2(m1);
2.const Maker1 m = m1;
3.const Maker1 m(m1);
4.const Maker1 m = m1;
5.进入死循环
*/
m2.printMaker1();
}
//编译器提供了默认的拷贝构造函数
//默认拷贝构造函数进行了成员变量的简单拷贝
class Maker2
{
public:
Maker2()
{
cout << "无参构造函数" << endl;
a = 20;
}
void printMaker2()
{
cout << "a=" << a << endl;
}
private:
int a;
};
void test2()
{
Maker2 m1;
m1.printMaker2;
Maker2 m2(m1);
m2.printMaker2;
}
int main()
{
test1();
test2();
system("pause");
return 0;
}
三.拷贝构造函数调用的时机
#define _CRT_SECIRE_NO_WARNINGS
#include <iostream>
using namespace std;
class Maker
{
public:
Maker()
{
cout << "无参构造函数" << endl;
}
Maker(int a)
{
cout << "有参构造函数" << endl;
}
Maker(const Maker &m)
{
cout << "拷贝构造函数" << endl;
}
~Maker()
{
cout << "析构函数" << endl;
}
};
//1.对象以值得方式给函数参数
void func1(Maker m) //Maker m = m1; 存在一个匿名对象
{
}
void test1()
{
Maker m1;
func1(m1);
}
//2.用一个已有对象去初始化另一个对象
void test2()
{
Maker m1;
Maker m2(m1);
}
//3.函数的局部对象以值的方式从函数返回
//vs Debug(调试)模式下,会调用拷贝构造
//vs Release(发行)模式下不会调永拷贝构造
//Qt也不调用拷贝构造
Maker func2()
{
Maker m; //局部对象
cout << "局部对象的地址:" << &m << endl;
return m;
}
void test3()
{
Maker m1 = func2();
cout << "m1对象的地址:" << &m1 << endl;
}
int main()
{
test1();
test2();
test3();
system("pause");
return 0;
}
四.匿名对象
#define _CRT_SECIRE_NO_WARNINGS
#include <iostream>
using namespace std;
class Maker
{
public:
Maker()
{
cout << "无参构造函数" << endl;
}
Maker(int a)
{
cout << "有参构造函数" << endl;
}
Maker(const Maker &m)
{
cout << "拷贝构造函数" << endl;
}
~Maker()
{
cout << "析构函数" << endl;
}
};
void test()
{
//匿名对象的声明周期在当前行
Maker();
Maker(10);
//注意:如果匿名对象有名字阶,那么久不是匿名对象
Maker m1 = Maker();
cout << "test()函数结束" << endl;
}
int main()
{
test();
system("pause");
return 0;
}
五.构造函数的分类及调用
构造函数的分类:
- 无参构造函数
- 有参构造函数
- 拷贝构造函数
#define _CRT_SECIRE_NO_WARNINGS
#include <iostream>
using namespace std;
class Maker1
{
public:
Maker1()
{
cout << "无参构造函数" << endl;
}
Maker1(int a)
{
cout << "有参构造函数" << endl;
}
Maker1(const Maker1 &m)
{
cout << "拷贝构造函数" << endl;
}
};
//构造函数的调用
void test1()
{
//常用:
Maker1 m1; //调用无参构造函数
Maker1 m2(10); //调用有参构造函数
Maker1 m3(m2); //调用拷贝构造函数
//不常用:
Maker1 m4 = Maker1(10); //调用的是有参构造函数
Maker1 m5 = m3; //调用拷贝构造函数
cout << "--------" << endl;
Maker1 m6 = 10; //Maker m6 = Maker(10);
cout << "--------" << endl;
Maker1 m7;
m7 = m6;//赋值操作
cout << "--------" << endl;
}
//1.如果程序员提供了有参构造
// 那么编译器不会提供默认构造函数
// 但是会提供默认的拷贝构造函数
class Maker2
{
public:
Maker2(int a)
{
cout << "有参构造函数" << endl;
}
};
void test2()
{
//Maker2 m; //err
Maker2 m(10); //调用有参构造函数
Maker2 m2(m); //调用拷贝构造函数
}
//2.如果程序员提供了拷贝构造函数
// 那么编译器不会提供默认的构造函数和默认的有参构造函数
class Maker3
{
Maker3(const Maker3 &m)
{
cout << "拷贝构造函数" << endl;
}
};
void test3()
{
//Maker3 m; //err
}
int main()
{
test1();
test2();
test3();
system("pause");
return 0;
}
[扩展] 类默认提供的函数:
- 默认的构造函数
- 默认的析构函数
- 默认的拷贝构造函数
- 默认的赋值函数
六.多个对象的构造和析构
- 如果类有成员对象
- 那么先调用成员对象的构造函数
- 再调用本身的构造函数
- 成员对象的构造函数调用和定义顺序一样
- 析构函数的调用顺序反之
注意:
- 如果有成员对象
- 那么实例化对象时
- 必须保证成员对象的构造和析构能被调用
#define _CRT_SECIRE_NO_WARNINGS
#include <iostream>
using namespace std;
class BMW
{
public:
BMW()
{
cout << "BMW构造" << endl;
}
~BMW()
{
cout << "BMW析构" << endl;
}
};
class Buick
{
public:
Buick()
{
cout << "Buick构造" << endl;
}
~Buick()
{
cout << "Buick析构" << endl;
}
};
class Maker
{
public:
Maker()
{
cout << "Maker构造" << endl;
}
~Maker()
{
cout << "Maker析构" << endl;
}
private:
Buick buick; //成员对象
BMW bmw; //成员对象
};
void test()
{
Maker m;
}
int main()
{
test();
system("pause");
return 0;
}
七.初始化列表
指定调用成员对象的某个构造函数
#define _CRT_SECIRE_NO_WARNINGS
#include <iostream>
using namespace std;
class BMW
{
public:
BMW(int a)
{
cout << "BMW有参构造" << endl;
}
~BMW()
{
}
};
class Buick
{
public:
Buick()
{
cout << "Buick构造" << endl;
}
Buick(int b, int c)
{
cout << "Buick有参构造" << endl;
}
~Buick()
{
}
};
class Maker
{
public:
//初始化列表
//注意1:初始化列表只能写在构造函数
Maker() :bmw(10)
{
cout << "Maker构造" << endl;
}
//注意2:如果有多个对象需要指定调用某个构造函数,用逗号隔开
Maker(int a, int b, int c) :bmw(a), buick(b, c)
{
cout << "Maker构造" << endl;
}
//注意3:如果使用了初始化列表,那么所有的构造函数都要写初始化列表
Maker(const Maker &m) :bmw(40), buick(10, 20)
{
cout << "Maker拷贝构造" << endl;
}
~Maker()
{
}
private:
//如果成员对象中给了有参构造函数
//编译器此时不会提供默认构造函数
//就会报错
//所以必须得提供无参构造函数
Buick buick; //成员对象
BMW bmw; //成员对象
};
void test()
{
Maker m1;
cout << "--------" << endl;
Maker m2(30, 10, 20);
cout << "--------" << endl;
Maker m3(m2);
}
int main()
{
test();
system("pause");
return 0;
}
八.对象的深浅拷贝
浅拷贝:
- 默认的拷贝构造函数进行的简单的赋值操作
- 会出现同一块空间被释放两次的问题
深拷贝:
- 自定义拷贝构造函数
- 可以解决浅拷贝带来的问题
#define _CRT_SECIRE_NO_WARNINGS
#include <iostream>
using namespace std;
class Student
{
public:
Student(const char* name, int Age)
{
pName = (char*)malloc(strlen(name) + 1);
strcpy(pName, name);
age = Age;
}
//自定义拷贝构造函数(进行深拷贝)
//解决浅拷贝问题
Student(const Student &s)
{
cout << "自定义拷贝构造函数" << endl;
//1.申请空间
pName = (char*)malloc(strlen(s.pName) + 1);
//2.拷贝数据
strcpy(pName, s.pName);
age = s.age;
}
~Student()
{
cout << "析构函数" << endl;
if (pName != NULL)
{
free(pName);
pName = NULL;
}
}
public:
char *pName;
int age;
};
void test()
{
Student s1("小花", 18);
Student s2(s1);
cout << "s1 Name=" << s1.pName << endl;
cout << "s1 age=" << s1.age << endl;
cout << "s2 Name=" << s2.pName << endl;
cout << "s2 age=" << s2.age << endl;
}
int main()
{
test();
system("pause");
return 0;
}