赞
踩
目录
面向对象的特点:封装、继承、多态
面向对象编程的特点:
(1)易维护:可读性高,即使改变了需求,由于继承的存在,只需要对局部模块进行修改,维护起来非常方便,维护的成本也比较低。
(2)质量高:可以重用以前项目中已经被测试过的类,使系统满足业务需求从而具有更高的质量
(3)效率高:在软件开发时,根据设计的需求要对现实世界的事物进行抽象,从而产生了类
(4)易扩展:由于继承、封装、多态的特性,可设计出高内聚、低耦合的系统结构,使系统更加灵活、更容易扩展,而且成本也比较低。
c++是一门面向对象的语言,理解c++,首先要理解类和对象
c++中的类可以看成c语言中的结构体的升级版,,结构体是一种构造类型,可以包含若干个成员变量,成员变量的类型可以不同。
关于class(类)的几点说明:
(1)类的定义的最后有一个分号,它是类的一部分,表示类定义结束,不能省略。
(2)一个类可以创建多个对象,每个对象都是一个变量
(3)类是一种构造类型,大小的计算方法和struct一样,需要字节对齐
(4)类成员变量的访问方法:通过 .或者->来访问
(5)成员函数是类的一个成员,出现在类中,作用范围由类来决定,而普通函数是独立的,作用范围是全局或者某个命名空间
struct :内部默认是共有权限,结构体外部可以访问其内部成员
class:内部默认是私有权限,类的外部不能直接访问内部成员;可以手动声明为共有权限;
public:公有属性,凡是在它下面声明的变量和函数,都可以在类的内部和外部访问
private:私有属性,凡是在它下面声明的变量和函数,只能在类的内部访问
protected:保护属性,凡是在它下面声明的变量和函数,只能在类的内部以及派生类(子类)中访问
类中有成员变量(属性)、成员函数(方法);
类可以创建对象;
举例:创建一个学生类(成员变量:年龄、姓名;成员方法:年龄输入、年龄输出)
注意:一个类中必须有输入与输出
头文件:student.h(含类创建)
- //student.h
- #ifndef _STUDENT_H_
- #define _STUDENT_H_
- #include <iostream>
- using namespace std;
- class Student
- {
- public:
- int GetAge(); //声明类的成员函数,在函数的其它地方实现
- int SetAge(int age);
- private:
- int m_age;
- char m_name[32];
- };
- #endif
方法体:student.cpp
- //Student.cpp
- #include "student.h"
- int Student::GetAge()
- {
- return m_age;
- }
- int Student::SetAge(int age)
- {
- m_age = age;
- }
主函数:main.cpp
- //main.cpp
- #include "student.h"
- int main(int argc, char const *argv[])
- {
- Student s1;
- s1.SetAge(18);
- cout<<s1.GetAge()<<endl;
- return 0;
- }
练习1:设计一个立方体类,求出立方体的面积(2ab + 2ac + 2bc)和体积(a*b*c),并且判断两个立方体是否相等
要求: 私有成员变量:长宽高
成员函数(方法):求面积,求体积,设置长宽高
全局函数:判断两个立方体是否相等
头文件:cube.h(含类创建)
- #ifndef _CUBE_H_
- #define _CUBE_H_
- #include <iostream>
- using namespace std;
- class Cube
- {
- private:
- int m_length;
- int m_wide;
- int m_high;
- public:
- //求面积
- int GetArea();
- //求体积
- int GetVolume();
- //设置长宽高
- void SetCube(int length,int wide,int high);
- //获取长度
- int GetLength();
- //获取高度
- int GetHight();
- //获取宽度
- int GetWide();
- };
- bool CubeIsEqual(Cube c1, Cube c2);
- #endif
方法体:cube.cpp
- #include "cube.h"
-
- int Cube::GetArea()
- {
- int MyArea = 2*m_high*m_length + 2*m_high*m_wide + 2*m_length *m_wide;
- return MyArea;
- }
-
- int Cube::GetVolume()
- {
- return m_high*m_length*m_wide;
- }
-
- void Cube::SetCube(int length,int wide,int high)
- {
- m_length = length;
- m_wide = wide;
- m_high = high;
- }
-
- //获取长度
- int Cube::GetLength()
- {
- return m_length;
- }
-
- //获取高度
- int Cube::GetHight()
- {
- return m_high;
- }
-
- //获取宽度
- int Cube::GetWide()
- {
- return m_wide;
- }
-
- bool CubeIsEqual(Cube c1, Cube c2)
- {
- if(c1.GetHight() == c2.GetHight() && c1.GetLength() == c2.GetLength() && c1.GetWide() == c2.GetWide())
- {
- return true;
- }
- else
- {
- return false;
- }
- }
主函数:main.cpp
- #include "cube.h"
-
- int main(int argc, char const *argv[])
- {
- Cube c1,c2; //创建对象
- c1.SetCube(1,2,3);
- c2.SetCube(1,3,2);
- cout<<"c1的面积是:"<<c1.GetArea()<<endl;
- cout<<"c2的面积是:"<<c2.GetArea()<<endl;
-
- cout<<"c1的体积是:"<<c1.GetVolume()<<endl;
- cout<<"c2的体积是:"<<c2.GetVolume()<<endl;
-
- if(CubeIsEqual(c1,c2))
- {
- cout<<"c1 = c2"<<endl;
- }
- else
- {
- cout<<"c1 != c2"<<endl;
- }
- return 0;
- }
练习2:设计一个圆形类和一个点类,计算点和圆的关系
要求:
1> 点类 属性:横坐标和纵坐标
方法:点和点之间的距离计算
设置横坐标,纵坐标
2> 圆形类 属性:半径 ,圆心 、
方法:计算点和圆的关系
设置半径和圆心
头文件:circle.h(含类创建)
- #ifndef _CIRCLE_H_
- #define _CIRCLE_H_
- #include <iostream>
- using namespace std;
-
- class Point
- {
- private:
- int m_x;
- int m_y;
- public:
- void setXY(int x,int y);
- int Distance(Point &p);
- };
- class Circle
- {
- private:
- Point m_center;
- int m_r;
- public:
- void SetC(int x,int y,int r);
- bool Judge(Point &p);
- };
-
- #endif
方法体:circle.cpp
- #include "circle.h"
-
- void Point::setXY(int x,int y)
- {
- m_x = x;
- m_y = y;
- }
-
- int Point::Distance(Point &p)
- {
- int dis = (p.m_x - m_x)*(p.m_x - m_x) + (p.m_y - m_y) *(p.m_y - m_y);
- return dis;
- }
-
- void Circle::SetC(int x,int y,int r)
- {
- m_center.setXY(x,y);
- m_r = r;
- }
-
- bool Circle::Judge(Point &p)
- {
- if(p.Distance(m_center) >= m_r *m_r)
- {
- return true;
- }
- else
- {
- return false;
- }
- }
主函数:main.cpp
- #include "circle.h"
- int main(int argc, char const *argv[])
- {
- Point p;
- p.setXY(0,3);
- Circle c1;
- c1.SetC(0,0,2);
- if(c1.Judge(p))
- {
- cout<<"点在圆上或者圆外"<<endl;
- }
- else
- {
- cout<<"点在圆内"<<endl;
- }
- return 0;
- }
在c++中,由一种特殊的成员函数,名字和类名相同,没有返回值,不需要用户显示调用(用户也不能调用),而是在创建对象的时候自动调用。 这种函数我们称为构造函数 关于构造函数:
1.函数名必须和类型相同
2.不能有返回值,函数体不能有return语句
3.构造函数在定义对象时会自动调用,不需要手动调用
- #include <iostream>
- #include <cstdlib>
- using namespace std;
-
- class Array
- {
- private:
- int *m_data; //数组的起始地址
- int m_size;
- public:
- Array(); //无参构造函数,函数名和类名一致,没有返回值
- void SetVal(int Index,int Val);
- int GetVal(int Index);
- ~Array(); //析构函数,函数名为:~类名 ,没有返回值,没有参数
- };
-
- Array::Array()
- {
- cout<<"Array的无参构造函数"<<endl;
- m_size = 5;
- m_data = (int *)malloc(sizeof(int) *m_size);
- }
-
- Array::~Array()
- {
- cout<<"Array的析构函数"<<endl;
- if(m_data != NULL)
- {
- free(m_data);
- m_data = NULL;
- }
- }
-
- int main(int argc, char const *argv[])
- {
- Array a1; //创建对象,会自动调用构造函数
-
- return 0;
- }
和普通函数一样,构造函数是允许重载的,一个类可以有多个重载的构造函数,在创建对象时根据传递实参来判断调用哪一个构造函数
- #include <iostream>
- #include <cstdlib>
- using namespace std;
-
- class Array
- {
- private:
- int *m_data; //数组的起始地址
- int m_size;
- public:
- Array(); //无参构造函数,函数名和类名一致,没有返回值
- Array(int s); //有参构造函数
- Array(int s,int z); //有两个参数的构造函数
-
- ~Array(); //析构函数,函数名为:~类名 ,没有返回值,没有参数
- };
-
- Array::Array()
- {
- cout<<"Array的无参构造函数"<<endl;
- m_size = 5;
- m_data = (int *)malloc(sizeof(int) *m_size);
- }
-
- Array::Array(int s) //有参构造函数
- {
- cout<<"Array的有一个参数的构造函数"<<endl;
- m_size = s;
- m_data = (int *)malloc(sizeof(int) * m_size);
- }
-
- Array::Array(int s,int z) //有两个参数的构造函数
- {
- cout<<"Array的有两个参数的构造函数"<<endl;
- m_size = s;
- m_data = (int *)malloc(sizeof(int) * m_size);
- }
-
- Array::~Array()
- {
- cout<<"Array的析构函数"<<endl;
- if(m_data != NULL)
- {
- free(m_data);
- m_data = NULL;
- }
- }
-
- int main(int argc, char const *argv[])
- {
- //Array a1(6); //括号法
- //Array a2(1,2); //调用两个参数的构造函数
- //Array a1 = 7; //等号法
- Array a3 = (1,2); //逗号表达式
- return 0;
- }
(1)概念
用一个现有的对象去初始化另一个对象
声明:Array(const Array &a); //拷贝构造函数
(2)拷贝构造函数的调用时机
1.用一个对象初始化另一个的对象
Array a1(a3);
Array a1 = a3;
Array a1 = Array(a3);
2.当函数的形参是一个对象时,例如:
void print(Array a) //Array a = a1;
{
a.GetVal(1);
}
3. 函数的返回值是一个对象
Array& Func()
{
Array a1;
return a1;
}
- #include <iostream>
- #include <cstdlib>
- using namespace std;
-
- class Array
- {
- private:
- int *m_data; //数组的起始地址
- int m_size;
- public:
- Array(); //无参构造函数,函数名和类名一致,没有返回值
- Array(const Array &a); //拷贝构造函数
-
- ~Array(); //析构函数,函数名为:~类名 ,没有返回值,没有参数
- };
-
- Array::Array()
- {
- cout<<"Array的无参构造函数"<<endl;
- m_size = 5;
- m_data = (int *)malloc(sizeof(int) *m_size);
- }
-
-
- Array::Array(const Array &a)
- {
- cout<<"Array的拷贝构造函数"<<endl;
- }
-
- Array::~Array()
- {
- cout<<"Array的析构函数"<<endl;
- if(m_data != NULL)
- {
- free(m_data);
- m_data = NULL;
- }
- }
-
- void print(Array a) //Array a = a1;
- {
- a.GetVal(1);
- }
-
- Array& Func()
- {
- Array a1;
- return a1;
- }
- int main(int argc, char const *argv[])
- {
- //Array a1;
- // Array a2 = a1;
- //print(a1);
- Array a2 = Func();
- return 0;
- }
深度拷贝:数据和内存空间都要拷贝;
- Array::Array(const Array &a) //深拷贝
- {
- cout<<"Array的拷贝构造函数"<<endl;
- m_size = a.m_size;
- m_data = (int *)malloc(sizeof(int) * m_size);
- for(int i = 0 ; i < m_size;i++)
- {
- m_data[i] = a.m_data[i];
- }
- }
当使用者没有提供构造函数,系统会提供默认构造函数;
当使用者提供了构造函数:
(1)提供了无参构造函数,编译器将不会再提供默认无参构造函数
(2)提供了有参构造函数,系统将不再提供无参构造函数
- #include <iostream>
- using namespace std;
- class Demo
- {
- public:
- /*Demo() //一旦提供了无参构造函数,编译器将不会再提供默认无参构造函数
- {
- cout<<"无参构造函数"<<endl;
- }*/
- Demo(int a) //一旦提供了有参构造函数,系统将不再提供无参构造函数
- {
- cout<<"DemO的有参构造函数"<<endl;
- }
- };
-
- int main(int argc, char const *argv[])
- {
- Demo d; //会提供默认的构造函数
- Demo d1 = d; //会提供默认的拷贝构造函数
- return 0;
- }
创建对象时系统会调用构造函数进行初始化工作,同样,销毁对象时系统也会自动调用一个函数进行清理工作,如释放分配的内存、关闭打开的文件等,这个函数就是析构函数。
格式:
~类名(); //析构函数
注意:析构函数没有参数,不能被重载,一个类只能有一个析构函数,如果用户没有定义析构函数,编译器会提供默认的析构函数。
- #include <iostream>
- #include <cstdlib>
- using namespace std;
- class Array
- {
- private:
- int *m_data; //数组的起始地址
- int m_size;
- public:
- Array(); //无参构造函数,函数名和类名一致,没有返回值
- Array(const Array &a); //拷贝构造函数
-
- ~Array(); //析构函数,函数名为:~类名 ,没有返回值,没有参数
- };
-
- Array::~Array()
- {
- cout<<"Array的析构函数"<<endl;
- if(m_data != NULL)
- {
- free(m_data);
- m_data = NULL;
- }
- }
-
- int main(int argc, char const *argv[])
- {
- //Array a1;
- // Array a2 = a1;
- //print(a1);
- Array a2 = Func();
- return 0;
- }
类名()//匿名对象,代码执行完毕,立即释放(不用到return)
- #include <iostream>
- using namespace std;
- class Test
- {
- public:
- Test()
- {
- cout<<"Test的无参构造函数"<<endl;
- }
- ~Test()
- {
- cout<<"Test的有参构造函数"<<endl;
- }
- };
- int main(int argc, char const *argv[])
- {
- Test(); //匿名对象,本行代码执行完,立即被释放
- cout<<"*******************"<<endl;
- return 0;
- }
new和delete:
- #include <iostream>
- #include <cstdlib>
- using namespace std;
- class Test
- {
- public:
- Test()
- {
- cout<<"Test的无参构造函数"<<endl;
- }
- Test(int a)
- {
- cout<<"有一个参数的构造函数"<<endl;
- }
- ~Test()
- {
- cout<<"Test的有参构造函数"<<endl;
- }
- };
- int main(int argc, char const *argv[])
- {
- //Test * t1 = (Test *)malloc(sizeof(Test));
- //free(t1);
- Test *pt = new Test(1); //会自动调用构造函数
- delete pt; //会自动调用析构函数
- return 0;
- }
使用情形:
//对象的初始化列表:
(1)类对象作为成员变量并且该类没有提供无参构造函数
(2)成员变量为const修饰
- #include <iostream>
- using namespace std;
- class Date
- {
- private:
- int m_year;
- int m_month;
- int m_day;
- public:
-
- Date(int y,int m,int d)
- {
- cout<<"Date的有参构造函数"<<endl;
- m_year = y;
- m_month = m;
- m_day = d;
- }
- };
-
- //对象的初始化列表:1.类对象作为成员变量并且该类没有提供无参构造函数 2.成员变量为const修饰
- class Student
- {
- private:
- const int m_id;
- Date birth;
- public:
- Student(int y,int m,int d,int i):birth(y,m,d),m_id(i)
- {
- cout<<"Student的有参构造函数"<<endl;
- }
- };
-
- int main(int argc, char const *argv[])
- {
- Student s1(1998,5,6,100);
- return 0;
- }
(1)普通函数可以访问静态成员变量
(2)静态成员变量一定要在类的外部初始化
(3)静态成员变量可以直接通过类名来访问
在c++中,静态成员变量属于某个类,而不属于某个对象,我们可以使用静态成员变量来实现多个对象共享数据的目标
class Student
{
static int m_num;
};
(1)静态成员函数中只能访问静态成员变量,不能访问普通变量
(2)静态成员函数中的静态成员变量可以通过类名访问
(3)普通成员函数不能通过类名访问
- #include <iostream>
- using namespace std;
- class Student
- {
- public:
- static int count;
- private:
- int id;
- public:
- Student()
- {
- count++;
- id = count;
- }
- int GetCount() //普通函数可以访问静态成员变量
- {
- return count;
- }
- static int GetCount1() //静态成员函数
- {
- return count; //静态成员函数中只能访问静态成员变量,不能访问普通变量
- }
- };
- int Student::count = 0; //静态成员变量一定要在类的外部初始化
- int main(int argc, char const *argv[])
- {
- Student s1;
- Student s2;
- cout<<s1.count<<endl;
- cout<<s2.count<<endl;
- cout<<Student::count<<endl; //静态成员变量可以直接通过类名来访问
- cout<<Student::GetCount1()<<endl;
- cout<<s1.GetCount()<<endl;
- return 0;
- }
在当前类的外部定义、不属于当前类的函数也可以在类中声明,但是要在前面加关键字friend, 这样就构成了友元函数。友元函数可以是不属于任何类的非成员函数,也可以是其他类的成员函数。
友元函数可以访问当前类中的所有成员,包括public、protected、private等属性的成员。
- #include <iostream>
- using namespace std;
-
- class Test
- {
- friend void show(Test &t); //将show函数声明为Test的友元,show可以访问Test的所有成员变量
- private:
- int m_a;
- public:
- void set(int a)
- {
- m_a = a;
- }
- };
-
- void show(Test &t)
- {
- cout<<t.m_a<<endl;
- }
-
- int main(int argc, char const *argv[])
- {
- Test t1;
- t1.set(2);
- show(t1); //通过友元函数可以访问,Test类中的所有成员。
- return 0;
- }
如果将类B声明为类A的友元类,那么类B中的所有成员函数都是类A的友元函数,类B就可以访问类A的所有成员,包括public、protected、private属性成员。
- #include <iostream>
- using namespace std;
-
- class A
- {
- friend class B; //声明B为A的友元,友谊具有单向性,不代表A是B的友元,破坏了他的封装性
- private:
- int m_a;
- public:
- void set(int a)
- {
- m_a = a;
- }
- };
-
- class B
- {
- private:
- int m_b;
- public:
- void print(A &a)
- {
- cout<<"m_a = "<<a.m_a<<endl;
- }
- };
-
- int main(int argc, char const *argv[])
- {
- A a1;
- a1.set(2);
-
- B b1;
- b1.print(a1); //当B成为A的友元类后,类B的所有成员函数都是A的友元函数,所以通过B的函数
- return 0; //可以访问A中所有成员。
- }
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。