网站建设需要机房服务器,扬州电子商务网站建设,互联网网站制作公司哪家好,网页特效经典300例C面向对象的三大特性#xff1a;封装、继承、多态。具有相同性质的对象#xff0c;抽象为类。 文章目录1 封装1.1 封装的意义#xff08;一#xff09;1.2 封装的意义#xff08;二#xff09;1.3 struct 和 class区别1.4 成员属性设置为私有练习案例#xff1a;1 设计… C面向对象的三大特性封装、继承、多态。具有相同性质的对象抽象为类。 文章目录1 封装1.1 封装的意义一1.2 封装的意义二1.3 struct 和 class区别1.4 成员属性设置为私有练习案例1 设计立方体类2 对象的初始化和清理2.1 构造函数和析构函数2.2 构造函数的分类及调用2.3 拷贝构造函数调用时机2.4 构造函数调用规则2.5 深拷贝与浅拷贝面试提及2.6 初始化列表2.7 类对象作为类成员2.8 静态成员1 封装
1.1 封装的意义一
将属性和行为作为一个整体表现为生活的事物将属性和行为加以权限控制
语法class 类名 { 访问权限 属性/行为}
示例设计一个圆类求圆的周长
/*设计一个圆类求圆的周长圆的周长公式 2 * PI * 半径
*/
const double PI 3.14;class Circle
{//访问权限
public://1、属性//半径int m_r;//2、行为//获取圆的周长double calculateZC(){return 2 * PI * m_r;}};
int main()
{system(color 1E);//通过圆类创建具体的圆c 实例化通过一个类实例化一个具体的对象Circle c1;//给圆对象的属性赋值c1.m_r 10;cout 圆的周长 c1.calculateZC() endl;system(pause); return 0;
}示例2设计一个学生类属性姓名、学号。给学生姓名和学号赋值然后显示出姓名和学号
class Student
{
public: // 访问权限 -公共权限//1、属性 :成员属性成员变量string s_name;int stuId;//2、行为 成员函数 成员方法void showStudent(){cout 学生的姓名 s_name 学号是 stuId endl;}//给姓名赋值void setName(string name){s_name name;}//给学号赋值void setId(int id){stuId id;}
};
int main()
{system(color 1E);//通过学生类创建具体那个学生 实例化通过一个类实例化一个具体的对象Student stu1;Student stu2;//给学生对象的属性赋值stu1.setName (张三);stu1.setId( 21202201);stu1.showStudent();stu1.s_name 李四;stu1.stuId 21202202;stu1.showStudent();system(pause); return 0;
}1.2 封装的意义二 说明类在设计时可以把属性和行为放在不同的权限下加以控制 访问权限三种
public公共权限 成员 类内可以访问类外也可以访问 protected保护权限 成员 类内可以访问类外不可以访问儿子可以访问父亲的保护内容 private私有权限 成员类内可以访问类外不可以访问儿子不可以访问父亲的私有内容
class Person
{public:string m_name;protected:string m_Car;private: int m_Password;public:void func(){m_name 张三;m_Car 保时捷;m_Password 12345;}
};1.3 struct 和 class区别 说明在C中struct 和class唯一的区别在于默认的访问权限不同 区别
struct默认权限为公共class默认权限为私有
class C1
{int m_a; //默认权限 私有
};struct C2
{int m_a; //默认权限 公共
};
C1 c1;
//c1.m_a 100; //报错
C2 c2;
c2.m_a 100; //公共权限类内类外都可以访问1.4 成员属性设置为私有
优点
将所有成员属性设置为私有之后自己可以控制读写权限对于写权限检测数据的有效性
#includeiostream
#includealgorithm
#includestring
using namespace std;/*成员属性设置为私有1、可以自己控制读写权限 --某些属性的读写2、对于以检测数据的有效性 --对于年龄的特殊设置*/
//设计人类
class Person
{
public://设置姓名void setName(string name){m_Name name;}//获取姓名string getName(){return m_Name;}int setAge(int age){m_Age 0;if (age 0 || age150){cout 你输入的年龄有误默认设置为0. endl;return m_Age;}m_Age age;}int getAge(){return m_Age;}void setLower(string lover){m_Lover lover;}private://姓名 可读可写string m_Name;//年龄 只读int m_Age;//情人 只写string m_Lover;};
int main()
{system(color 1E);Person p;p.setName(唐三);cout 输入的姓名 p.getName()endl;//检测数据的有效性p.setAge(1000);cout 输入的年龄 p.getAge()endl; //年龄只读p.setLower(小舞); //情人只能可写return 0;
}练习案例
1 设计立方体类
求出立方体的面积和体积。分别用全局函数和成员函数判断两个立方体是否相等 #includeiostream
#includealgorithm
#includestring
using namespace std;/*立方体的类的设计1、创建立方体类2、设计属性3、设计行为 获取立方体面积和体积4、分别利用全局函数和成员函数 判断两个立方体是否相等*/
class Cube
{public:void setL(double l) {m_L l;}void setW(double w) {m_W w;}void setH(double h) {m_H h;}double getL() {return m_L;}double getW() {return m_W;}double getH() {return m_H;}//获取立方体的面积double getArea(){double area;area 2 * (m_H*m_L m_H * m_W m_L * m_W);return area;}//获取立方体的体积double getVolu(){double volume;volume m_H * m_L * m_W ;return volume;}//利用成员函数判断两个立方体是否相等bool isSameByClass(Cube c){if (m_L c.m_L m_H c.m_H m_W c.m_W){return true;}return false;}private:double m_L, m_W, m_H;};//全局函数判断两个函数是否相等
bool isSameByClasss(Cube c1, Cube c2)
{if (c1.getL() c2.getL() c1.getH() c2.getH() c1.getW() c2.getW()){return true;}return false;
}int main()
{system(color 1E);Cube c,c1,c2;c.setL(1);c.setW(2);c.setH(3);c1.setL(2);c1.setW(2);c1.setH(2);c2.setL(2);c2.setW(2);c2.setH(3);cout 立方体的面积 c.getArea() endl;cout 立方体的体积 c.getVolu() endl;bool gouRet isSameByClasss(c1, c2);if (gouRet true){cout 全局函数的两个立方体是相等的 endl;}elsecout 全局函数的两个立方体是不相等的 endl;bool ret c1.isSameByClass(c2);if (ret true){cout 两个立方体是相等的 endl;}elsecout 两个立方体是不相等的 endl;return 0;
}2 对象的初始化和清理
生活中有些电子产品都有出厂设置每个对象初始设置以及对象销毁前的清理数据的设置
2.1 构造函数和析构函数
对象的初始化和清理是重要的安全问题
一个对象或者变量没有初始状态对其使用后果也是未知的同样使用完一个对象或变量没有及时清理也会造成 一定的安全问题
C利用构造函数和析构函数解决上述问题这两个函数会被编译器自动调用 完成对象初始化和清理工作。若是不提供构造和析构编译器会提供构造函数和析构函数是空实现的自己不写有人写
构造函数主要作用于创建对象时为对象的成员属性赋值构造函数由编译器自动调用无需手动析构函数作用于对象销毁前自动调用执行一些清理 工作。
构造函数语法 类名(){ }
1 构造函数没有返回值也不写void2 函数名称与类明相同3 构造函数可以有参数因此可以重载4 程序在调用对象的时候会自动调用构造无需 手动调用且只调用一次
析构函数语法 ~类名(){ }
1 析构函数没有返回值不写void2 函数名称与类名相同在名称前面加上符合 ~3 析构函数不可以有参数因此不能发送重载4 程序在对象销毁前会自动调用析构无需手动调用只调用一次
class Person
{
public:Person(){cout 正在构造函数 endl;}~Person(){cout 正在析构函数 endl;}
};
void test01()
{Person p;
}
int main()
{test01();return 0;
}2.2 构造函数的分类及调用
两种分类方式 按照参数分有参构造和无参构造 Person(){cout 无参的构造函数调用 endl;}Person(int a){age a;cout 有参的构造函数调用 endl;}按照类型分普通构造和拷贝构造 //拷贝构造函数/*定义若是有张三这个人然后用李四去克隆张三这个人的属性不过张三本身属性不能改变加上 const只读*/Person(const Person p){age p.age;}三种调用方式 括号法(一般这个比较好 ) 注意若是无参的函数构造不要写p1()这样会被认为是函数的声明 //1、括号法Person p1;//有参构造函数Person p2(10);cout p2的年龄为 p2.age endl;//拷贝构造函数Person p3(p2);cout p3的年龄为 p3.age endl;显示法 注意Person(10)若是在左侧则是匿名对象执行结束后系统立马回收匿名对象函数 Person p1;
//有参构造函数
Person p2 Person(10);
//拷贝构造函数
Person p3 Person(p2);隐式转换法 Pensor p410; //相当于写了Person p4Person(10) 有参构造
Pensor p5p3; //拷贝构造2.3 拷贝构造函数调用时机
C拷贝构造函数调用时机通常有三种情况 使用一个已经创建完毕的对象来初始化一个对象 值传递的方式给函数参数传值 void doWork(Person p)
{
}
void test()
{Person p; //默认构造函数doWork(p);//拷贝构造函数给函数的p
}以值的方式返回局部对象 Person doWork()
{Person p1;return p1; //返回p1的时候也会产生一个拷贝构造函数。返回会重新生成一个跟p1一样的数据
}
void test()
{Person p doWork();
}2.4 构造函数调用规则
默认情况下只要创建类C编译器至少给应该类添加3个函数
默认构造函数无参为空默认析构函数无参为空默认拷贝析构函数对属性的值进行拷贝
构造函数调用规则如下
如果用户定义有参构造函数C不提供默认无参构造但会提供默认拷贝构造如果用户定义拷贝构造函数C不再提供其他构造函数有参、无参
2.5 深拷贝与浅拷贝面试提及
浅拷贝简单的赋值拷贝编译器做-》会导致堆区的内存重复释放 深拷贝在堆区重新申请空间进行拷贝操作
class Person
{
public:int age;int * Height;//构造函数Person(){cout 无参的构造函数调用 endl;}Person(int a,int height){age a;//用new在堆区创建一个对象Height new int(height);cout 有参的构造函数调用 endl;}//自己实现拷贝构造函数 解决浅拷贝带来的问题Person(const Person p){cout Person 拷贝构造函数调用 endl;age p.age;//Height p.Height; 编译器默认实现这行代码//在堆区重新申请空间进行深拷贝Height new int(*p.Height);}//析构函数~Person(){//释放堆区创建的内存if (Height ! NULL){delete Height;Height NULL;}//作用析构代码将堆区开辟数据做释放cout 正在析构函数 endl;}
};
//调用
void test01()
{//p1走自己的析构p2也是自己的析构Person p1(18, 180);cout p1的年龄为 p1.age 身高为 *p1.Height endl; //*表示指针的实际化输出的是一个值不是地址Person p2(p1);cout p2的年龄为 p2.age 身高为 *p2.Height endl;
}说明若是使用指针就会在堆区使用内存空间p1和p2两个对象然后两个对象指向同一块内存delete是释放对象指向的内存这里用浅拷贝会被释放两次。 2.6 初始化列表 说明C提供初始化列表语法用来初始化属性 语法构造类名()属性1(值1)属性2(值2) . . . { }
1传统初始化列表
class Person
{
public:int m_A;int m_B;int m_C;//传统列表赋初值Person(int a, int b, int c){m_A a;m_B b;m_C c;}
};
void test()
{Person p(10, 20, 30);cout m_A p.m_A endl;cout m_A p.m_B endl;cout m_A p.m_C endl;
}改进之后的
Person(int a,int b,int c):m_A(a),m_B(b),m_C(c)
{
}2.7 类对象作为类成员 说明C类中的成员可以是另一个类的对象称为该成员为对象成员。当其他类对象作为本类对象构造的时候先构造其他类对象再构造自身对象。析构的时候先释放自身内存 再释放其他对象内存。 //创建手机的类
class Phone
{
public:string m_Pname;Phone(string name){m_Pname name;cout 正在调用手机类的构造函数 endl;}~Phone(){cout 正在调用手机类的析构函数 endl;}
};
class Person
{
public:string m_Name;Phone m_Phone;Person(string name, string phone):m_Name(name),m_Phone(phone){cout 正在调用Person类的构造函数 endl;}~Person(){cout 正在调用Person类的析构函数 endl;}
};
//调用
void test01()
{Person p(张三, 苹果14pro);cout p.m_Name 拿着 p.m_Phone.m_Pname 手机 endl;}2.8 静态成员
静态成员就是想在成员变量和成员函数前加上关键字static称为静态成员
静态成员分为
1静态成员变量
所有对象共享一份数据若是p1.a100若是p2也调用p2.a200则p1.a200;a是共享的在编译阶段分配内存类内声明类外初始化在类外声明一个类内定义的属性初始化int Person::a100)类外访问不到私有静态成员变量。私有成员变量访问不到
class Person
{
public:static int m_Age;
};
int Person::m_Age 100;Person p;
//访问方式一通过对象
cout p.m_Age endl; -100
//访问方式二通过类名
coutPerson::m_Ageendl; -100
Person p1;
p1.m_Age 200;
cout p.m_Age endl; -200 //修改了2静态成员函数
所有对象共享一个函数静态成员函数只能访问静态成员变量非静态成员变量函数无法区分到底是那个对象的属性而静态成员变量所有人共享一份不属于任何人。私有成员函数访问不到