类的相关内容:
基础知识 :
//面向对象的三大特性: 封装,继承,多态
//首先是封装: 语法: class 类名 {访问权限: 属性/行为 };案例:设计一个圆类,计算它的周长
#includeusing namespace std;const double pi = 3.14; class circle { public :void change(int x);void show();private:int r; }; void circle::change(int x) {r = x; } void circle::show() {cout << "圆的周长为:" << 2 * pi * r << endl; } int main() {circle c1;//使用类时,必须要实例化一个对象出来,不然不能访问其属性和行为int r=0;cout << "请输入您要计算的圆的半径:" << endl;cin >> r;c1.change(r);c1.show(); } 案例2:设计一个学生类,属性有姓名和学号,
可以给姓名和学号赋值,可以显示学生的姓名和学号#includeusing namespace std; #include class Student { private:string s_name;string s_number; public:void changestudent(string , string );void show(); }; void Student ::changestudent(string name, string number) {s_name = name;s_number = number;} void Student::show() {cout << "姓名为:" << s_name << endl;cout << "学号为:" << s_number << endl; } int main() {Student s;string name;string number;cout << "请输入学生姓名:" << endl;cin >> name;cout << "请输入学生学号:" << endl;cin >> number;s.changestudent(name,number);cout << "录入完毕!请查看" << endl;s.show(); }
struct 和 class 的区别:
struct 默认权限为公有 class 默认权限为私有
成员属性设置为私有的好处:
①(控制权限)将左右成员属性设置为私有,可以自己控制读写权限:
可以通过 public: 中添加行为(函数),
来作为桥梁控制私有属性和行为 :可以返回 ,写入 操作
② 设置范围,避免犯错 :
比如:
void setage (int age) //设计年龄写入的范围
{
if(age <0 || age >150)
{
cout << "您输入有误,请重新输入"<m_age = 0;
return;
}
//否则赋值:
m_age = age;
}
案例①
设计立方体类(cube)
求出立方体的面积和体积
分别用全局函数和成员函数判断两个立方体是否相等#includeusing namespace std;class Cube { public://求出面积void area();//求出体积double volume();void change(double, double, double);int fanH(){return m_h;}int fanl(){return m_l;}int fanW(){return m_w;}//用成员函数判断两个立方体相不相等:void func3(Cube s1,Cube s2){if (s1.m_h == s2.m_h && s1.m_l == s2.m_l && s1.m_w == s2.m_w ){cout << "从成员函数中判断:两个立方体相等!" << endl;}elsecout << "从成员函数中判断:两个立方体不相等!" << endl;} private:double m_h;double m_l;double m_w; }; void Cube::change(double h, double l, double w) {m_h = h; //高m_l = l; //长m_w = w; //宽 } double Cube::volume() //定义求体积的函数 {double V = m_h * m_l * m_w;cout << "体积为:" << V << endl;return V; } void Cube::area() //定义求体积的函数 {double area = (m_h *m_w* 2) + (m_l * m_w* 2) + (m_l* m_h * 2);cout << "面积为:" << area << endl; } //用全局函数判断两个立方体是否相等:长宽高必须分别相等 // 因为全局函数中无法调用 私有成员 所以必须要从类中返回长宽高 void func(double h1,double i1,double w1,double h2,double i2,double w2) {if (h1==h2 &&i1==i2 && w1 ==w2){cout << "两个立方体相等!" << endl;}elsecout << "两个立方体不相等!" << endl; }int main() {Cube s1,s2;cout << "第一个立方体:" << endl;s1.change(5.1, 8.7,9.1);s1.area();s1.volume();cout << "第二个立方体:" << endl;s2.change(5.6, 8.4, 8.58);s2.area();s2.volume();//从类中返回长宽高int h1 = s1.fanH();int i1 = s1.fanl();int w1 = s1.fanW();int h2 = s2.fanH();int i2 = s2.fanl();int w2 = s2.fanW();//判断是否相等func(h1, i1, w1, h2, i2, w2);s1.func3(s1,s2); }
案例2 :
自己敲的版本: 圆形固定在了(0,0)点 不灵活
#includeusing namespace std; #include class circle { public://声明一个计算两点之间距离的公式:void sumD(double c_x, double c_y,double r);double countD();double fanr(){return c_r;} private:double c_x; //点的坐标x值double c_y; //点的坐标y值double c_r; //圆的半径 }; void circle::sumD(double x,double y,double r) {c_x = x;c_y = y;c_r = r; } double circle::countD() {int d = sqrt(pow(c_x, 2) + pow(c_y, 2));return d; } int main() {circle s;s.sumD(5.6, 9.2, 8.4);double d = s.countD();double r = s.fanr();if (d == r){cout << "点在圆上" << endl;}else if (d > r){cout << "点在圆外" << endl;}else if (d < r){cout << "点在圆内" << endl;} } 提高版本:圆心也是任意的, 传入和调用参数的时候 用到引用
构造函数 和 析构函数 :
对象的初始化和清理也是两个非常重要的安全问题:
①一个对象或者变量没有初始化状态,对其使用后果也是未知的
②同样的使用完一个对象或者变量,没有及时清理,也会造成一定的安全问题
解决:
c++中用构造函数和析构函数解决以上问题,这两个函数会被编译器自动调用
,如果我们不提供构造和析构,编译器会提供空实现的(构造和析构函数)。
构造函数:
主要作用在于创建对象时为对象的成员属性赋值,由编译器自动调用(无需手动)
构造函数语法:
- 类名(){ }
- 没有返回值也不写void
- 构造函数可以有参数,因此可以发生重载
- 无需手动调用 ,而且只会调用一次。
析构函数:
主要作用于在对象销毁前系统自动调用,执行一些清理工作。
析构函数语法:
- ~ 类名 (){ }
- 析构函数也不用写返回值 ,也不写void
- 函数名称与类名相同,在名称前加上符号~
- 析构函数不可以有参数,因此不可以发生重载
- 无需手动调用 ,而且只会调用一次。
构造函数的分类和调用:
//构造函数的分类和调用
//分类: 按照参数分类 无参构造 和有参构造#includeusing namespace std; class person { public://构造函数person(){cout << "person 无参构造函数的调用" << endl;}person(int a){age = a;cout << "person有参构造函数调用:" << endl;cout << "age = " << age << endl;}//析构函数~person(){cout << "person 析构函数的调用" << endl;} public:int age; }; void func() //括号法调用 : {/*调用默认无参构造函数时: 不要加上括号 person p1();编译器会自动认为是函数的声明,而不是在创建对象。*/person p1; // 无参构造函数的调用person p2(10); //有参构造函数的调用person p3(p2);// 拷贝构造函数的调用cout << "输出p3拷贝p2后age的值" << p3.age << endl; } void func02() // 显式法调用: {person p1;person p2 = person(10);person p3 = person(p2);//person(10);// 匿名对象 :调用后就会立刻销毁//不要利用拷贝构造函数初始化匿名对象 , person(p3);//编译器会认为 person p3 重定义 : person (p3) == person p3; } void func03()//隐式调用 {person p4 = 10; //有参 //编译器会自动转换为: person p4 = person(10);person p5 = p4;//编译器自动转换为: person p5 = person(p4); } int main() {//func(); //括号法调用//试着输出 p3拷贝后的 age 值 不可以!! //因为person 的 对象p3 是在 void函数中定义的所以主函数中无法访问//func02(); // 显式调用func03(); //隐式调用}
拷贝构造函数调用时机:
c++ 中拷贝构造函数调用时机通常有三种情况:
① 使用一个已经创建完毕的对象初始化一个新对象
②值传递的方式给函数参数返回传值
③ 以值的方式返回局部变量#includeusing namespace std;class person { public:person(){cout << "person无参构造函数的调用" << endl;}person(int age){m_age = age;cout << "person有参构造函数的调用" << endl;}~person(){cout << "person析构函数的调用" << endl;} person(const person& p) {m_age = p.m_age ; //这里一定要注意:如果拷贝构造函数不去接受传入的数据,则输出时会显示乱码cout << "person拷贝构造函数的调用" << endl; } int m_age; }; void func01() //① 使用一个已经创建完毕的对象初始化一个新对象 {person p1(10);cout << "输出p1.age=" << p1.m_age << endl;person p2(p1);cout << "拷贝后输出p2.age = " <
构造函数的调用规则:
默认情况下,c++编译器至少给一个类添加三个函数
1.默认构造函数(无参,函数体为空)
2.默认析构函数(无参,函数体为空) 因为析构函数不可以发生重载
3.默认拷贝构造函数,对属性进行值拷贝
构造函数调用规则如下 (高级屏蔽低级,低级提供高级)
1.如果用户定义有参构造函数,c++不再提供默认无参构造。依然提供拷贝构造
如果我们自己不写默认构造函数,则编译器不会提供默认构造函数,会编译错误
2.如果用户定义拷贝构造函数,c++不再 提供其他构造函数。
如果我们自己不写,则c++不再提供默认构造和析构函数 ,会编译报错
深拷贝与浅拷贝
浅拷贝:简单的赋值拷贝操作(编译器自带的)
深拷贝:在堆去重新申请空间,进行拷贝操作 (要我们自己去定义一个拷贝函数)
如果不利用深拷贝在堆区创建新内存,会导致浅拷贝带来的重复释放堆区问题
代码:
#includeusing namespace std;class person {public:int m_age;int *m_height; //用了指针 就需要在堆区自己开辟一条内存person ()//默认构造{cout <<"默认构造函数的调用"< 总结:如果属性有在堆区开辟的,一定要自己提供拷贝构造函数,防止浅拷贝带来的问题
析构函数中检验是否为空指针的部分可以用:
if (ptr == nullptr) {// 检查指针是否为空std::cout << "指针为空" << std::endl; }
初始化列表:
初始化列表的几种方法:
第一种: 传统方法:
person(int a,int b,int c) //传统方法初始化{m_a =a;m_b =b;m_c =c;}第二种:列表法:
person(int a,int b,int c):m_a(a),m_b(b),m_c(c) {} //也可以直接写成 person(int a,int b,int c):m_a(13),m_b(14),m_c(520) {} 但是不灵活,值设定有局限性。综合:
#includeusing namespace std;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; // }//列表法:person(int a,int b,int c):m_a(a),m_b(b),m_c(c) {}//也可以直接写成 person(int a,int b,int c):m_a(13),m_b(14),m_c(520) {} 但是不灵活,值设定有局限性。 }; void func01() {person p(13,14,520);cout << "赋值后的值为:"<
类对象作为类成员:
语法: (与结构体嵌套类似)
class A{ } class B { A a; }B 类中有对象A作为成员, A为对象成员.
创建对象时: 副类的构造函数先调用, 主类的构造函数后调用
释放对象时:主类的析构函数先调用,副类的析构函数后调用。
#includeusing namespace std; #include class phone { public:string pname;phone (string pname){m_phonename = pname;cout <<"副类的构造函数调用"<
静态成员变量:
静态成员 :静态成员在成员变量和成员函数前加上关键字static,称为静态成员
静态成员分为:
静态成员变量:
1.所有对象共享同一份数据
静态成员变量不属于某个对象上 ,所有对象都同用一份数据。
2.在编译阶段分配内存(全局区)
3.类内声明 ,类外初始化
类外初始化 : 数据类型 类名 :: 成员名 = 初始化数值;
4.只能访问公有权限的static成员,私有static成员在类外不可以访问
5.静态成员变量访问的两种方式:
//1、通过对象 Person p1; p1.m_A = 100; cout << "p1.m_A = " << p1.m_A << endl;//2、通过类名 : 类名 :: 成员名 cout << "m_A = " << Person::m_A << endl; //cout << "m_B = " << Person::m_B << endl; //私有权限访问不到整体代码:
#includeusing namespace std; class person { public:static int a ; private: static int m_a; }; int person :: a = 100; int person :: m_a = 120; void func() {person p;cout <<"用成员在public中调用:"< 静态成员函数:
所有对象共享同一个函数
1.怎么在类外访问静态成员函数
2.静态成员函数只能访问静态成员变量
class Person {public://静态成员函数特点://1 程序共享一个函数//2 静态成员函数只能访问静态成员变量static void func(){cout << "func调用" << endl;m_A = 100;//m_B = 100; //错误,不可以访问非静态成员变量}static int m_A; //静态成员变量int m_B; // private://静态成员函数也是有访问权限的static void func2(){cout << "func2调用" << endl;} }; int Person::m_A = 10;void test01() {//静态成员变量两种访问方式//1、通过对象Person p1;p1.func();//2、通过类名Person::func();//Person::func2(); //私有权限访问不到 }int main() {test01();system("pause");return 0; }
本文来自互联网用户投稿,文章观点仅代表作者本人,不代表本站立场,不承担相关法律责任。如若转载,请注明出处。 如若内容造成侵权/违法违规/事实不符,请点击【内容举报】进行投诉反馈!
