类和对象
1.封装
1.1 封装
#include<iostream>
using namespace std;
#include<string>
//class 类名{访问权限:属性/行为}
//圆的周长公式:s=2*π*r。
const double pi = 3.14;
//class代表设计一个类,类后面紧跟着的就是类名称
//类中的属性和行为都称为“成员”
//属性 成员属性,成员变量
//行为 成员函数,成员方法
class circle//圆类
{
//访问权限
public:
//属性,一般都是一些变量
int m_r;//半径
//行为,一般都是函数
//获取圆的周长
double calculatezc()
{
return 2 * pi*m_r;
}
};
int main()
{
//通过圆类 创建具体的圆;
//实例化(通过一个类 创建一个对象的过程)
circle c1;//对象
//给圆对象 的属性进行赋值
c1.m_r = 10;
cout << "圆的周长为:" << c1.calculatezc() << endl;
system("pause");
return 0;
}
1.2 设计学生类
设计一个学生类,属性有姓名和学号,可以给姓名和学号赋值,可以显示学生的姓名和学号。
class student
{
//访问权限-公共权限
public:
//属性,一般是变量
string m_name;
int m_id;
//行为
void showstudent()
{
cout << "姓名:" << m_name << " 学号" << m_id << endl;
}
//也可以给姓名赋值
void setname(string name)
{
m_name = name;
}
void setid(int id)
{
m_id = id;
}
};
int main()
{
//实例化对象
student s1;
//给属性赋值
//s1.m_name = "胖子";
s1.setname("胖子");
//s1.m_id = 1;
s1.setid(1);
//显示学生信息
s1.showstudent();
/*student s2;
s2.m_name = "嫖客";
s2.m_id = 2;
s2.showstudent();*/
system("pause");
return 0;
}
1.3三种保护权限
public 公共权限 : 成员类内可以访问,类外可以访问。
protected 保护权限 : 成员类内可以访问,类外不可以访问儿子可以访问父亲的保护内容。
private 私有权限 : 成员类内可以访问,类外不可以访问儿子不可以访问父亲的私有内容。
//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 = 123456;
}
};
int main()
{
person p1;
p1.m_name = "李四";
//p1.m_car = "奔驰" //类外访问不了
system("pause");
return 0;
}
1.4 struct和class的区别
struct和class唯一的区别在于默认的访问权限的不同.
struct默认为共有。
class默认为私有。
class c1
{
int m_a;
};
struct c2
{
int m_a;
};
int main()
{
c1 c1;
//c1.m_a = 100;//报错,class默认私有
c2 c2;
c2.m_a = 100;
system("pause");
return 0;
}
1.5 成员属性设为私有
可以自己控制读写权限。
对于写可以检测数据的有效性。
class person
{
public:
//设置姓名
void setname(string name)
{
m_name = name;
}
//获取姓名
string getname()
{
return m_name;
}
//获取年龄
int getage()
{
m_age = 0;
return m_age;
}
//设置年龄
void setage(int age)
{
if (age < 150 && age>0)
{
m_age = age;
}
else
{
m_age = 0;
cout << "你这个老妖" << endl;
return;
}
}
void setlover(string lover)
{
m_lover = lover;
}
private:
//姓名 可读可写
string m_name;
//年龄 只读
int m_age;
//情人 只写
string m_lover;
};
int main()
{
person p;
p.setname("张三");
cout << "姓名为:" << p.getname() << endl;
p.setage(1000);
cout << "年龄为:" << p.getage() << endl;
//p.setlover = "胖子";//数据无法访问,只写
//cout << "情人为:" << p.getlover() << endl;
system("pause");
return 0;
}
1.6 练习案例1
设计立方体类。
求出立方体的面积和体积。
分别用全局函数和成员函数判断两个立方体是否相等。
class cube
{
//访问权限
public:
//属性
int m_l;
int m_w;
int m_h;
void set_l(int l)
{
m_l = l;
}
int get_l()
{
return m_l;
}
void set_w(int w)
{
m_w = w;
}
int get_w()
{
return m_w;
}
void set_h(int h)
{
m_h = h;
}
int get_h()
{
return m_w;
}
//行为
int cube_volume()
{
return m_l*m_w*m_h;
}
int cube_surface_area()
{
return 2 * (m_l*m_w + m_l*m_h + m_w*m_h);
}
void issame(cube &c)//用局部函数进行判断时,只要传一个参数就行了,本身自带一个,然后传入一个,就可以进行对比了
{
if (cube_surface_area() == c.cube_surface_area() && cube_volume() == c.cube_volume())
{
cout << "这两个立方体相等" << endl;
}
else
{
cout << "这两个立方体不相等" << endl;
}
}
};
//全局函数
void issame(cube &c1,cube &c2)
{
if (c1.cube_surface_area() == c2.cube_surface_area() && c1.cube_volume() == c2.cube_volume())
{
cout << "这两个立方体相等" << endl;
}
else
{
cout << "这两个立方体不相等" << endl;
}
}
int main()
{
cube c1;
cout << "请输入第一个立方体的长 宽 高" << endl;
cin >> c1.m_l;
cin >> c1.m_w;
cin >> c1.m_h;
//c1.set_l(10);//这样也可以滴
//c1.set_w(10);
//c1.set_h(10);
cout << "第一个立方体的表面积为" << c1.cube_surface_area()<<endl;
cout << "第一个立方体的体积积为" << c1.cube_volume() << endl;
cube c2;
cout << "请输入第二个立方体的长 宽 高" << endl;
cin >> c2.m_l;
cin >> c2.m_w;
cin >> c2.m_h;
cout << "第二个立方体的表面积为" << c2.cube_surface_area() << endl;
cout << "第二个立方体的体积积为" << c2.cube_volume() << endl;
//issame(c1, c2);
/*if (c1.cube_surface_area() == c2.cube_surface_area() && c1.cube_volume() == c2.cube_volume())//放到全局函数中
{
cout << "这两个立方体相等" << endl;
}
else
{
cout << "这两个立方体不相等" << endl;
}*/
c1.issame(c2);// 学会这个哦
system("pause");
return 0;
}
1.7 自己的案例练习2
设计一个圆形类,和一个点类,计算点和圆的关系。
class circle
{
//访问权限
public:
//属性
int cx; //圆心的横坐标
int cy; //圆心的纵坐标
int cr; //圆的半径
void set_x(int x)
{
cx = x;
}
int get_x()
{
return cx;
}
void set_y(int y)
{
cy = y;
}
int get_y()
{
return cy;
}
void set_r(int r)
{
cr = r;
}
int get_r()
{
return cr;
}
//行为
};
class point
{
public:
int px; //点的横坐标
int py; //点的纵坐标
void set_x(int x)
{
px = x;
}
int get_x()
{
return px;
}
void set_y(int y)
{
py = y;
}
int get_y()
{
return py;
}
};
void relation(circle &c1,point &p1)
{
if (sqrt((c1.get_x() - p1.get_x())*(c1.get_x() - p1.get_x()) + (c1.get_y() - p1.get_y())*(c1.get_y() - p1.get_y())) < c1.get_r())
{
cout << "点在圆的里面" << endl;
}
else if (sqrt((c1.get_x() - p1.get_x())*(c1.get_x() - p1.get_x()) + (c1.get_y() - p1.get_y())*(c1.get_y() - p1.get_y())) == c1.get_r())
{
cout << "点在圆上" << endl;
}
else
{
cout << "点在圆的外面" << endl;
}
}
int main()
{
circle c1;
c1.set_x (0);
c1.set_y(0);
c1.set_r(1);
point p1;
p1.set_x(0);
p1.set_y(1);
relation(c1, p1);
system("pause");
return 0;
}
1.8 课程的的案例2做法
设计一个圆形类,和一个点类,计算点和圆的关系。
class point
{
private:
int px; //点的横坐标
int py; //点的纵坐标
public:
void set_x(int x)
{
px = x;
}
int get_x()
{
return px;
}
void set_y(int y)
{
py = y;
}
int get_y()
{
return py;
}
};
class circle
{
//访问权限
private:
//属性
point m_center;//圆心
int cr; //圆的半径
public:
void set_r(int r)
{
cr = r;
}
int get_r()
{
return cr;
}
void setcenter(point center)
{
m_center = center;
}
point getcenter()
{
return m_center;
}
};
void isincircle(circle &c,point &p)
{
//计算两点之间的距离的平方
int distance = (c.getcenter().get_x() - p.get_x())*(c.getcenter().get_x() - p.get_x()) + (c.getcenter().get_y() - p.get_y())*(c.getcenter().get_y() - p.get_y());
//计算半径的平方
int rdistance = c.get_r()*c.get_r();
if (distance < rdistance)
{
cout << "点在圆的里面" << endl;
}
else if (distance == rdistance)
{
cout << "点在圆上" << endl;
}
else
{
cout << "点在圆的外面" << endl;
}
}
int main()
{
//创建圆
circle c1;
c1.set_r(10);
//创建点
point center;
center.set_x(0);
center.set_y(0);
c1.setcenter(center);
point p1;
p1.set_x(10);
p1.set_y(0);
isincircle(c1, p1);
system("pause");
return 0;
}
2.对象特性
2.1构造函数和析构函数
#include<iostream>
#include<string>
using namespace std;
//对象的初始化和清理
//1.构造函数 进行初始化操作
class person
{
public:
//1.1 构造函数
//没有返回值,也没有void
//函数名 与类名相同
//构造函数可以有参数,可以发送重载
//创建对象的时候,构造函数会自动调用,有且只有一次
person()
{
cout << "person构造函数的调用" << endl;
}
//析构函数 进行清理的操作
//没有返回值 不写void
//函数名和类名相同 在名称前面加~
//析构函数不可以有参数,不可以重载
//销毁对象前,析构函数会自动调用,有且只有一次
~person()
{
cout << "person析构函数的调用" << endl;
}
};
//构造和析构都是必须有的实现,如果我们不提供,编译器会提供一个空实现的构造和析构
void test01()
{
person p;//在栈上的数据,test01执行完毕后,释放这个对象
}
int main()
{
test01();//创建对象的时候,构造函数会自动调用,有且只有一次
//or
//person p;//看得到构建,因为析构会在你任意键结束后的一瞬间出现,看不怎么到。
system("pause");
return 0;
}
2.2 构造函数的分类和调用
//构造函数的分类和调用
//分类
class person
{
public:
// 构造函数
int age;
person()//无参
{
cout << "person无参构造函数的调用" << endl;
}
person(int a)//有参构造
{
age = a;
cout << "person有参构造函数的调用" << endl;
}
//拷贝构造
person(const person &p)
{
age = p.age;
cout << "person拷贝构造函数的调用" << endl;
}
//析构函数
~person()
{
cout << "person析构函数的调用" << endl;
}
};
void test01()
{
//1.括号法
person p1;//默认无参构造函数的调用
person p2(10);//有参构造函数的调用
person p3(p2);//拷贝构造函数的调用
//注意事项
//调用默认构造函数时候,不要加()
//person p1(),因为这行代码,编译器会认为是一个函数的声明,不会认为在创建对象
cout << "p2的年龄为:" << p2.age << endl;
cout << "p3的年龄为:" << p3.age << endl;
//2.显示法
person p1;
person p2 = person(10);//有参构造, person(10)叫做匿名对象,特点:当前行执行结束后,系统会立即回收匿名对象
person p3 = person(p2);//拷贝构造
//注意事项2
//不要利用拷贝构造函数初始化匿名对象,比如person(p3)
//3.隐式转换法
person p4 = 10;//相当于person p4=person p4=person(10);有参构造
}
int main()
{
test01();
system("pause");
return 0;
}
2.3 拷贝构造函数的调用时机
class person
{
public:
//构造函数
person()
{
cout << "person默认无参构造函数的调用" << endl;
}
person(int age)
{
cout << "person有参构造函数的调用" << endl;
m_age = age;
}
person(const person &p)
{
cout << "person拷贝构造函数的调用" << endl;
m_age =p.m_age ;
}
//析构函数
~person()
{
cout << "person析构函数的调用" << endl;
}
int m_age;
};
//1.使用一个已经创建完毕的对象来初始化一个新对象
void test01()
{
person p1(20);
person p2(p1);
cout << "p2的年龄:" << p2.m_age << endl;
}
//2.值传递的方式给函数参数传值
void dowork(person p)
{
}
void test02()
{
person p;
dowork(p);
}
//3.以值方式返回局部对象
person dowork2()
{
person p1;
return p1;
}
void test03()
{
person p = dowork2();
}
int main()
{
//test01();
//test02();
test03();
system("pause");
return 0;
}
2.4 构造函数调用规则
1.创建一个类,c++编译器会给每个类都添加至少3个函数:
默认构造(空实现),
析构函数(空实现),
拷贝构造(值拷贝)。
2.如果我们写了有参构造函数,编译器就不再提供默认构造,依然提供拷贝构造。
3.如果我们写了拷贝构造函数,编译器就不再提供其他构造函数。
class person
{
public:
person()
{
cout << "person的默认无参构造函数" << endl;
}
person(int age)
{
m_age = age;
cout << "person的有参构造函数" << endl;
}
person(const person &p)
{
m_age = p.m_age;
cout << "person的拷贝构造函数" << endl;
}
~person()
{
cout << "person的析构函数" << endl;
}
int m_age;
};
void test01()
{
person p1;
p1.m_age = 18;
person p2(p1);
cout << "p2的年龄:" << p2.m_age << endl;
}
void test02()
{
person p(28);
person p2(p);
cout << "p2的年龄:" << p2.m_age<<endl;
}
int main()
{
//test01();
test02();
system("pause");
return 0;
}
2.5 深拷贝和浅拷贝
class person
{
public:
person()
{
cout << "person的默认无参构造函数" << endl;
}
person(int age, int height)
{
m_age = age;
m_height = new int( height );
cout << "person的有参构造函数" << endl;
}
//自己实现一个拷贝构造函数,解决浅拷贝带来的问题
person(const person &p)
{
cout << "拷贝函数调用" << endl;
m_age = p.m_age;
//m_height = p.m_height;编译器默认实现的就是这行代码
//深拷贝操作:
m_height = new int(*p.m_height);
}
~person()
{ //比如我在堆区开辟了一个内存,那个么析构函数的作用就出现了,将堆区开辟的数据释放
if (m_height != NULL)
{
delete m_height;
m_height = NULL;
}
cout << "person的析构函数" << endl;
}
int m_age;
int *m_height;//身高
};
void test01()
{
//浅拷贝带来的问题就是堆区的内存重复释放,利用深拷贝解决
//在没有深拷贝前,下面这个代码会崩掉
person p1(18,160);
cout << "p1的年龄:" << p1.m_age<<"p1的身高:"<<*p1.m_height<<endl;
person p2(p1);
cout << "p2的年龄:" << p2.m_age << "p1的身高:" << *p2.m_height<< endl;
}
int main()
{
test01();
system("pause");
return 0;
}
2.6初始化列表
感觉没啥用,哈哈哈哈哈哈哈哈哈哈!!!!!!!
class person
{
public:
person() :m_age(20), m_height(160)
{
cout << "年龄:" <<m_age<< endl;
cout<<"身高:"<< m_height << endl;
}
int m_age;
int m_height;
};
void test01()
{
person p;
}
int main()
{
test01();
system("pause");
return 0;
}
2.7类对象作为类成员
class phone
{
public:
phone(string pname)
{
cout << "phone的构造函数调用" << endl;
m_pname = pname;
}
~phone()
{
cout << "phone的析构函数调用" << endl;
}
//手机品牌名称
string m_pname;
};
class person
{
public:
//phone m_phone =pname;隐式转换法
person(string name, string pname):m_name(name), m_phone(pname)
{
cout << "person的构造函数调用" << endl;
}
~person()
{
cout << "person的析构函数调用" << endl;
}
string m_name;
phone m_phone;
};
//当其他类的对象作为本类成员,构造时候先构造类对象,再构造自身
void test()
{
person p("张三", "苹果手机");
cout << p.m_name << "拿着" <<p.m_phone.m_pname << endl;
}
int main()
{
test();
system("pause");
return 0;
}
2.8 静态成员-静态成员变量
class person
{
public:
//1.所有对象都共享同一份数据
//2.编译阶段就分配内存
//3.类内声明,类外初始化操作
static int m_a;
//静态成员变量也是有访问权限的
private://类外访问不到私有的
static int m_b;
};
int person:: m_a = 100;//第三点 类内声明,要类外初始化操作
int person::m_b = 200;
void test()
{
person p;
cout << p.m_a << endl;
person p2;
p2.m_a = 200;
cout << p2.m_a << endl;
cout << p.m_a << endl;//也变成200了。共享数据
}void test02()
{
//静态成员变量 不属于某个对象上,所有对象都共享同一份数据
//因此静态成员变量有两种访问方式
//1.通过对象进行访问
person p;
cout << p.m_a << endl;
//2.静态的还可以通过类名进行访问
cout << person::m_a << endl;
}
int main()
{
test();
system("pause");
return 0;
}
2.9 静态成员-静态成员函数
所有对象共享同一个函数。
静态成员函数只能访问静态成员变量。
class person
{
public:
//静态成员函数
static void func()
{
m_a = 100;//静态成员函数只能访问静态成员变量
//m_b = 100;//报错,因为不是静态的,因为无法区分m_b到底是哪个对象的属性
cout << "static void func调用" << endl;
}
static int m_a;//静态成员变量
int m_b;
};
int person::m_a =0;
void test()
{
//通过对象访问
person p;
p.func();
//通过类名访问
person::func();
}
int main()
{
test();
system("pause");
return 0;
}
2.10 成员变量和成员函数
分开存储.
class person
{
public:
int m_a;//非静态成员变量,属于类对象上
static int m_b;//静态成员变量,不属于类对象上
void func()//非静态成员函数,不属于类对象
{
}
static void func2()//静态成员函数,不属于类对象
{}
};
int person::m_b = 10;
void test()
{
person p;
//空对象占用的内存空间:1
//C++编译器会给每个空对象也分配一个字节空间,是为了区分空对象占内存的位置
//每个空对象也应该有一个独一无二的内存地址
cout << "sizeof p=" << sizeof(p) << endl;
}
void test02()
{
person p;
cout << "sizeof p=" << sizeof(p) << endl;
}
int main()
{
//test();
test02();
system("pause");
return 0;
}
2.11 this指针
class person
{
public:
person(int age)
{//this指针指向的是被调用的成员函数的对象
this->age = age;
}
person& personaddage(person &p)
{
this->age += p.age;
//this指向p2的指针,而*this指向的是p2这个对象的本体
return *this;
}
int age;
};
//1.解决名称冲突
void test01()
{
person p1(18);
cout << "p1的年龄:"<<p1.age << endl;
}
//返回对象本身用*this
void test02()
{
person p1(10);
cout << "p1的年龄:" << p1.age << endl;
person p2(10);
p2.personaddage(p1).personaddage(p1).personaddage(p1);
cout << "p2的年龄:" << p2.age << endl;
}
int main()
{
//test01();
test02();
system("pause");
return 0;
}
2.12 空指针访问成员函数
class Person
{
public:
void showClassName()
{
cout << "this is person class" << endl;
}
int m_age;
void showPersonAge()
{
//报错原因:传入的指针为空
//所以加入判断
if (this == NULL)
{
return ;
}
cout << "age=" << this->m_age<<endl;
}
};
void test01()
{
Person *p = NULL;
p->showClassName();
// p->showPersonAge;//运行这个会报错,为什么呢,看上面的解释
}
int main()
{
test01();
system("pause");
return 0;
}
2.13const修饰成员函数
//常函数
class person
{
public:
//this指针的本质 是指针常量 指针的指向是不可以修改的
//const person*canst this;
//在成员函数后面加const,修饰的是this指向,让指针指向的值也不可以修改
void showperson()const
{
this->m_b = 100;
//this->m_a = 100;
//this->NULL;//this指针不可以修改指针的指向的
}
void func()
{
m_a = 100;
}
int m_a;
mutable int m_b;//特殊变量,即使在常函数中,也可以修改这个值
};
void test()
{
person p;
p.showperson();
}
//常对象
void test02()
{
const person p;//在对象前加上const,变为常对象
//p.m_a = 100;//不可以改,会报错
p.m_b = 100;//m_B是特殊值,在常对象下也可以修改
//常对象只能调用常函数
p.showperson();
//p.func();//不允许,报错,因为常对象不允许调用普通成员函数,因为普通成员函数可以修改属性
}
int main()
{
test();
system("pause");
return 0;
}