面向对象三大特性:封装、继承、多态
封装
封装的意义
1.将属性和行为作为一个整体,表现生活中的事物 语法:calss 类名{ 访问权限:属性 / 行为};
示例
#include<iostream> #include<string> using namespace std; const double PI = 3.14; //定义圆周率 class Circle //class代表设计一个类,类后面紧跟着的就是类名称 { public://访问权限中的公共权限 int m_r;//属性:定义圆的半径 double perimeter() //行为:获取圆的周长 { return 2 * PI * m_r; } }; int main() { //实例化,通过一个类创建一个对象的过程 //(通过圆类,创建具体圆的对象:周长) Circle c1; c1.m_r = 10;//给圆对象的属性进行赋值 cout << "c1周长为: " << c1.perimeter() << endl; return 0; }
2.将属性和行为加以权限控制 三种访问权限: public 公共权限 类内可以访问,类外可以访问 protected 保护权限 类内可以访问,类外不可以访问 pirvate 私有权限 类内可以访问,类外不可以访问
在类内函数func中,函数可以访问公共权限的m_Name,保护权限的m_car,私有权限的m_password
而在类外函数main中,函数只能访问公共权限的m_Name
struct和class的区别
class作为类其默认的访问权限为私有,struct作为类时其默认访问权限为公有
成员属性设置为私有
1.将所以成员属性设置为私有,可以自己控制读写权限
#include<iostream> #include<string> using namespace std; class Li { public: void setName(string Name)//设置名字可写 { m_Name = Name; } string getName() //设置名字可读 { return m_Name; } string getcar() //设置汽车可读 { return m_car; } void setpassword(int password) { m_password= password ;//设置密码可写 } private: string m_Name;//可读可写 string m_car="奔驰"; //可读不可写 string m_password; //可写不可读 }; int main() { Li c1; c1.setName("wang");//名字设置 cout << "名字为:" << c1.getName() << endl; //获取名字 cout << "汽车为: " << c1.getcar() << endl; //获取汽车 c1.setpassword(); //密码设置 return 0; }
2.对于写权限我们可以自己检测数据的有效性
#include<iostream> #include<string> using namespace std; const double PI = 3.14; class Li { public: void setage(int age) { if (age<0 || age > 150)//对于写权限我们可以自己检测数据的有效性 { cout << "您输入的年龄" << age << "有误,请更正!" << endl; return; } m_age=age; } int getage() { return m_age; } private: int m_age=0; }; int main() { Li c1; c1.setage(60); cout << "年龄为:" << c1.getage() <<"岁" << endl; return 0; }
若输出值超过150或者小于0则会显示
对象的初始化和清理
构造函数和析构函数
构造函数进行初始化操作
语法:类名(){}
1.构造函数没有返回值也不写void
2.函数名称与类名相同
3.函数可以有参数,因此可以发生重载
4.程序在调用对象时会自动调用构造,无需手动调用,而且只会调用一次
析构函数 进行清理操作
语法:~类名(){}
1.构造函数没有返回值也不写void
2.函数名称与类名相同在名称前加~
3.函数不可以有参数,因此不可以发生重载
4.程序在对象销毁前会自动调用析构,无需手动调用,而且只会调用一次
*构造和析构都必须有如果我们不提供,编译器自动提供一个空实现的构造和析构
#include<iostream> #include<string> using namespace std; class person { public: person() { cout << "person的构造函数调用" << endl; } ~person() { cout << "person的析构函数调用" << endl; } }; void test01() { person p; } int main() { test01(); system("pause"); return 0; }
函数的分类以及调用
#include<iostream> #include<string> using namespace std; class person { public: int age; //按参数分为:有参构造和无参构造(默认构造) person() { cout << "person的无参构造调用" << endl; } person(int a) { age = a; cout << "person的有参构造调用" << endl; } //按类型分为:拷贝构造和普通构造(有参构造和无参构造)、 person(const person &p) //相当于传入一个person到参数按照这个person拷贝一份 { age = p.age; cout << "person的拷贝构造调用" << endl; } }; void test01() { //括号法调用 person p1;/*无参构造调用 调用无参构造时不要加() 否则编译器会认为这是一个函数的声明不是在创建对象*/ person p2(10); //有参构造调用 person p3(p2); //拷贝构造调用 cout << "p2的年龄:" << p2.age << endl; cout << "p3的年龄" << p3.age << endl; //对p2进行拷贝 } int main() { test01(); return 0; }
显示法和隐式转化法调用
#include<iostream> #include<string> using namespace std; class person { public: int age; //按参数分为:有参构造和无参构造(默认构造) person() { cout << "person的无参构造调用" << endl; } person(int a) { age = a; cout << "person的有参构造调用" << endl; } //按类型分为:拷贝构造和普通构造(有参构造和无参构造)、 person(const person &p) //相当于传入一个person到参数按照这个person拷贝一份 { age = p.age; cout << "person的拷贝构造调用" << endl; } }; void test01() { //显示法调用 person p1;//无参构造调用 person p2= person(10); //有参构造调用 person p3=person (p2); //拷贝构造调用 cout << "p2的年龄:" << p2.age << endl; cout << "p3的年龄" << p3.age << endl; //隐式转化法 person p4 = 10; //相当于写了person p4= person(10) person p5 = p4; } int main() { test01(); return 0; }
拷贝构造函数调用时机
1.使用一个已经创建完毕的的对象来初始化一个新对象
#include<iostream> #include<string> using namespace std; class person { public: int age; person() { cout << "person的无参构造函数调用" << endl; } person(int a) { age = a; cout << "person的有参构造函数调用" << endl; } person(person &p) { age = p.age; cout << "person的拷贝构造函数调用" << endl; } ~person() { cout << "person的无参析构函数调用" << endl; } }; //1.使用一个已经创建完毕的的对象来初始化一个新对象 void test01() { person p1(20); person p2(p1); cout << "p2的年龄为:" << p2.age << endl; } int main() { test01(); system("pause"); return 0; }
2..值传递的方式给函数参数传值 #include #include using namespace std; class person { public: int age; person() { cout << "person的无参构造函数调用" << endl; } person(int a) { age = a; cout << "person的有参构造函数调用" << endl; } person(person &p) { age = p.age; cout << "person的拷贝构造函数调用" << endl; }
~person() { cout << "person的无参析构函数调用" << endl; }
}; //2.值传递的方式给函数参数传值 void dowork(person p) {
} void test02() { person p; dowork(p); }
int main() { test02();
system("pause"); return 0;
}
#include<iostream> #include<string> using namespace std; class person { public: int age; person() { cout << "person的无参构造函数调用" << endl; } person(int a) { age = a; cout << "person的有参构造函数调用" << endl; } person(person &p) { age = p.age; cout << "person的拷贝构造函数调用" << endl; } ~person() { cout << "person的无参析构函数调用" << endl; } }; //3.值方式返回局部对象 person dowork2() { person p1; return p1; } void test03() { person p = dowork2();//这里发生错误不懂问完再改 } int main() { test03(); system("pause"); return 0; }
构造函数调用规则
默认情况下,编译器至少给一类三 个函数 1.默认构造函数(无参,函数体为空) 2.默认析构函数(无参,函数体为空) 3.默认拷贝构造函数,对属性进行值拷贝
构造函数调用规则如下: 如果用户定义有参构造函数,则编译器不再提供默认无参构造,但会提供默认拷贝构造 如果用户定义拷贝构造函数,则编译器不再提供其他构造函数
深拷贝和浅拷贝
浅拷贝:简单的赋值拷贝操作 深拷贝:在堆区重新申请空间,进行拷贝操作
浅拷贝:
#include<iostream> #include<string> using namespace std; class Person { public: int m_age; int *m_height; Person() { cout << "Presond的默认构造函数调用" << endl; } Person(int age,int height) { m_age = age; m_height = new int(height);//用指针去接受堆区的数据 cout << "Presond的有参构造函数调用" << endl; } ~Person() { //析构代码将堆区开辟数据做释放操作 if (m_height != NULL /*(空的意思)*/) { delete m_height; m_height = NULL;//释放后防止野指针的出现将其置空 } cout << "Presond的析构函数调用" << endl; } }; void test01() { Person p1(18,180); cout << "p1 age:" << p1.m_age<<"p1 height"<<p1.m_height << endl; Person p2(p1); cout << "p2 age:" << p2.m_age << "p2 height" << p2.m_height << endl;//我们没有提供拷贝构造函数,编译器做了浅拷贝的操作给我们提供了一个拷贝构造函数 } int main() { test01(); system("pause"); return 0; }
运行截图:
浅拷贝问题:堆区内存重复释放
解决办法利用深拷贝开辟一块新的内存区域
#include<iostream> #include<string> using namespace std; class Person { public: int m_age; int* m_height; Person() { m_height = nullptr; cout << "Presond的默认构造函数调用" << endl; } Person(int age, int height) { m_age = age; m_height = new int(height);//用指针去接受堆区的数据 cout << "Presond的有参构造函数调用" << endl; } Person(const Person& p) { m_age = p.m_age; //m_height = p.m_height;编译器默认实现的就是这行代码 //进行深拷贝操作 m_height = new int(*p.m_height); } ~Person() { //析构代码将堆区开辟数据做释放操作 if (m_height != nullptr /*(空的意思)*/) { delete m_height; m_height = nullptr;//释放后防止野指针的出现将其置空 } cout << "Presond的析构函数调用" << endl; } }; void test01() { Person p1(18, 180); cout << "p1 age:" << p1.m_age << "p1 height:" << *p1.m_height << endl; Person p2(p1); cout << "p2 age:" << p2.m_age << "p2 height:" << *p2.m_height << endl; } int main() { test01(); system("pause"); return 0; }
初始化列表
作用:c++提供初始化列表语法,用于初始化属性
语法:构造函数():属性1(值1),属性1(值1),...{}
#include<iostream> #include<string> using namespace std; class preson { public: preson(int a, int b, int c) :m_A(a), m_B(b),m_C(c){} void printperson() { cout << "a=" << m_A << endl; cout << "b=" << m_B << endl; cout << "c=" << m_C << endl; } private: int m_A; int m_B; int m_C; }; int main() { preson p (20,30,40); p.printperson(); system("pause"); return 0; }
类对象作为类成员
#include<string> using namespace std; //类对象作为类成员 class phone { public: phone(string PName) { m_PName = PName; } string m_PName; //手机品牌名称 }; class person { public: //phone m_PName = PName;(隐式转换法) 编译器自动利用PName给m_PName进行构造调用 person(string Name, string PName) :m_Name(Name), m_PName(PName) { } string m_Name; phone m_PName; }; void test() { person p("张三", "华为"); cout << p.m_Name << "拿着" << p.m_PName.m_PName<<"手机" << endl; } int main() { test(); system("pause"); return 0; }
版权声明:
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。
如若内容造成侵权、违法违规、事实不符,请将相关资料发送至xkadmin@xkablog.com进行投诉反馈,一经查实,立即处理!
转载请注明出处,原文链接:https://www.xkablog.com/cjjbc/690.html