1 类和对象的概念和关系
类是对现实生活中一类具有共同属性和行为的事物的抽象
类的特点:1.类是对象的数据类型 2.类是具有相同属性和行为的一组对象的集合
什么是对象的属性? 属性: 对象具有的各种特征,每个对象的每个属性都拥有特定的值
什么是对象的行为? 行为:对象能够执行的操作
类和对象的关系 :
类:类是对现实生活中一类具有共同属性和行为的事物的抽象 对象:是能够看得到摸得着的真实存在的实
1.1 访问权限
类在设计时,可以把属性和行为放在不同的权限下,加以控制访问权限有三种:
1.public公共权限 2. protected保护权限 3. private私有权限
#include<iostream>
using namespace std;
class Person
{
public:
string m_name;
protected:
string m_car;
private:
int m_password;
public:
void func()
{
m_name = "sss";
m_car = "aaaaaaaaaaaaaa";
m_password = 1111111111111;
}
};
int main() {
Person p1;
p1.m_name = "aaaaaaaasssssssss";
//p1.m_car = "sadsfsfsafa";
void func();
cout<<p1.m_name<<endl; //公有权限,所以可以改变
system("pause");
return 0;
}
1.2 struct和class的区别
在C++中struct和class唯一的区别就在于默认的访问权限不同区别:
struct 默认权限为公共 class默认权限为私有
#include<iostream>
using namespace std;
class C1
{
int m_a; //私有
};
struct C2
{
int m_a; //公共
};
int main() {
C1 c1; //实例化对象
c1.m_a = 100; //不可以访问
C2 c2;
c2.m_a = 100; //可以访问
system("pause");
return 0;
}
1.3 成员属性私有化
优点1:将所有成员属性设置为私有,可以自己控制读写权限
优点2:对于写权限,我们可以检测数据的有效性
#include<iostream>
using namespace std;
class Person
{
public:
//提供一点公共的接口让你操作吧
//以函数的形式实现可读可写
//设置姓名
public:
void setname(string name)
{
m_name = name;
}
//获取姓名
string getname()
{
return m_name;
}
//年龄是只读的
int getage()
{
int m_age = 999;
return m_age;
}
//只写权限 //这个函数接口没有读出的语句
void setlover(string lover)
{
m_lover = lover;
}
private:
//name 可读可写
string m_name;
//age 只读
string m_age;
//情人 只写
string m_lover;
};
int main() {
Person p1;
p1.setname("张三");
cout << "姓名为" << p1.getname() << endl;
cout << "年龄为" << p1.getage() << endl;
//设置情人
p1.setlover("仓井");
//cout <<"情人为" << p1.m_lover<<endl; //不可访问咯!!!
system("pause");
return 0;
}
1.4 案例-设计立方体类
#include<iostream>
using namespace std;
//1 创建立方体类
//2 设计属性
//3 设计行为,获取面积,体积
//4 分别利用全局函数和成员函数,判断立方体是否相等
class Cube
{
public:
//设置长
void setl(int l )
{
m_l = l;
}
//获取长
int getl()
{
return m_l;
}
//设置宽
void setw(int w)
{
m_w = w;
}
//获取宽
int getw()
{
return m_w;
}
//设置高
void seth(int h)
{
m_h = h;
}
//获取高
int geth()
{
return m_h;
}
//获取立方体面积
int calculaetS()
{
return 2 * m_l * m_w + 2 * m_w * m_h + 2 * m_l * m_h;
}
//获取立方体体积
int calculateV()
{
return m_l * m_w * m_h;
}
//成员函数判断两个立方体是否相等
bool issamebyclass(Cube &c2)
{
if (m_l == c2.getl() && m_w == c2.getw() && m_h == c2.geth())//自身的长宽高和传进来的长宽高进行对比判断
{
return true;
}
return false;
}
private:
int m_l;
int m_w;
int m_h;
};
//利用全局函数判断两个立方体是否相同
bool issame(Cube c1, Cube c2)
{
if (c1.getl() == c2.getl() && c1.getw() == c2.getw() && c1.geth() == c2.geth())
{
return true;
}
return false;
}
int main() {
//实例化对象
Cube c1;
c1.seth(10);
c1.setl(10);
c1.setw(10);
cout << "体积为" << c1.calculaetS() << endl;
cout << "面积为" << c1.calculateV() << endl;
//创建第二个立方体
Cube c2;
c2.seth(10);
c2.setl(10);
c2.setw(10);
//全局函数,开始判断
bool ret = issame(c1, c2);
if (ret)
{
cout<<"全局函数,开始判断,体积是相等的" << endl;
}
else
{
cout << "体积不是相等的" << endl;
}
//成员函数开始判断
ret = c1.issamebyclass(c2);
if (ret)
{
cout << "成员函数开始判断,体积是相等的" << endl;
}
else
{
cout << "体积不是相等的" << endl;
}
system("pause");
return 0;
}
1.5 案例-点和圆的关系
#include<iostream>
using namespace std;
//点类
class point
{
public:
//设置x
void setx(int x)
{
m_x = x;
}
//获取x
int getx()
{
return m_x;
}
//设置y
void sety(int y)
{
m_y = y;
}
//获取y
int gety()
{
return m_y;
}
private:
int m_x;
int m_y;
};
//圆类
class circle
{
public:
//设置半径
void setr(int r)
{
m_r = r;
}
//获取半径
int getr()
{
return m_r;
}
//设置圆心
void setcenter(point center)
{
m_center = center;
}
//获取圆心
point getcenter()
{
return m_center;
}
private:
int m_r;
point m_center;
};
//判断点和圆的关系
void isincircle(circle& c, point& p)
{
//计算两点之间的距离 平方
int distance =
(c.getcenter().getx() - p.getx()) * (c.getcenter().getx() - p.getx()) +
(c.getcenter().gety() - p.gety()) * (c.getcenter().gety() - p.gety());
//计算半径的平方
int rdistance =
c.getr() * c.getr();
//判断关系
if (distance = rdistance)
{
cout<<"点在圆上" << endl;
}
else if (distance > rdistance)
{
cout << "点在圆外" << endl;
}
else
{
cout << "点在圆内" << endl;
}
}
int main2() {
//创建圆
circle c;
c.setr(10);
point center;
center.setx(10);
center.sety(0);
c.setcenter(center);
//创建点
point p;
p.setx(10);
p.sety(10);
//判断关系
isincircle(c, p);
system("pause");
return 0;
}
2 对象的初始化和清理
生活中我们买的电子产品都基本会有出厂设置,在某一天我们不用时候也会删除一些自己信息数据保证安全。
C++中的面向对象来源于生活,每个对象也都会有初始设置以及对象销毁前的清理数据的设置。
2.1 构造函数和析构函数
对象的初始化和清理也是两个非常重要的安全问题,一个对象或者变量没有初始状态,对其使用后果是未知,同样的使用完一个对象或变量,没有及时清理,也会造成—定的安全问题。
C++利用了构造函数和析构函数解决上述问题,这两个函数将会被编译器自动调用,完成对象初始化和清理工作。对象的初始化和清理工作是编译器强制要我们做的事情,因此如果我们不提供构造和析构,编译器会提供编译器提供的构造函数和析构函数是空实现。
构造函数:主要作用在于创建对象时为对象的成员属性赋值,构造函数由编译器自动调用,无须手动调用。·
析构函数:主要作用在于对象销毁前系统自动调用,执行一些清理工作。
构造函数语法: | 析构函数语法: |
---|---|
1.构造函数,没有返回值也不写void | 1.析构函数,没有返回值也不写void |
2.函数名称与类名相同 | ⒉.函数名称与类名相同,在名称前加上符号~ |
3.构造函数可以有参数,因此可以发生重载 | 3.析构函数不可以有参数,因此不可以发生重载 |
4.程序在调用对象时候会自动调用构造,无须手动调用,而且只会调用一次 | 4.程序在对象销毁前会自动调用析构,无须手动调用,而且只会调用一次 |
#include<iostream>
using namespace std;
//构造函数 初始化
//析构函数 清理
class person
{
public:
//构造函数
person()
{
cout << "构造函数" << endl;
}
//析构函数
~person()
{
cout<<"析构函数" << endl;
}
};
void test01()
{
cout <<"aaaa" << endl;
person p; //站上的数据,执行完毕后,就会释放这个对象
}
int main4() {
test01();
system("pause");
return 0;
}
2.2 构造函数的分类以及调用
两种分类方式:
按参数分为:有参构造和无参构造
按类型分为:普通构造和拷贝构造
三种调用方式:括号法显示法隐式转换法
#include<iostream>
using namespace std;
//分类
class person
{
public:
//普通函数
//构造函数
person()
{
cout << "构造函数" << endl;
}
//有参构造函数
person(int a )
{
age = a;
cout << "youcan构造函数" << endl;
}
//拷贝构造函数
person(const person &p)
{
age = p.age;
cout << "拷贝构造函数" << endl;
//将传入的人的所有属性,拷贝到他身上
}
//析构函数
~person()
{
cout << "析构函数" << endl;
}
int age;
};
//调用
void test01()
{
//1 括号法
//person p1;//默认构造
//person p2(10);//有参构造
//person p3(p2);//拷贝构造
//cout << "p2年龄" << p2.age<<endl;
//cout << "p3年龄" <<p3.age <<endl;
//注意 1 :
//调用默认构造函数,不要加(),因为编译器会认为这是一个函数的声明
//person p1();
//2 显示法
person p1;//默认构造
person p2 = person(10);//有参构造
person p3 = person(p2);//拷贝构造
//person(10) 匿名对象。 特点:当前行执行结束后,系统就会回收了;
//注意 2 :
//不要利用拷贝构造, 初始化匿名对象 , 编译器会认为 person(p3) == person p3; 对象声明
//person (p3);
//3 隐式转换法
person p4 = 10; //有参构造
person p5 = p4;//拷贝构造
}
int main() {
test01();
system("pause");
return 0;
}
2.3 拷贝构造函数调用时机
C++中拷贝构造函数调用时机通常有三种情况
1.使用一个已经创建完毕的对象来初始化一个新对象·
2.值传递的方式给函数参数传值
3.以值方式返回局部对象
#include<iostream>
using namespace std;
//拷贝构造函数调用时机
//1 使用一个已经创建完毕的对象来初始化一个新对象
//2 值传递的方式给函数参数传值
//3 值方式返回局部对象
class person
{
public:
//构造函数
person()
{
cout << "默认构造函数" << endl;
}
person(int age)
{
m_age = age;
cout << "有参构造函数" << endl;
}
//拷贝构造函数
person(const person& p)
{
m_age = p.m_age;
cout << "拷贝构造函数" << endl;
//将传入的人的所有属性,拷贝到他身上
}
//析构函数
~person()
{
cout << "析构函数" << 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;
cout<<(int*)&p1<<endl;
return p1;
}
void test03()
{
person p = dowork2();
cout << (int*)&p << endl;
}
int main() {
//test01();
test03();
system("pause");
return 0;
}
2.4 构造函数调用规则
默认情况下,C++编译器至少给一个类添加3个函数
1.默认构造函数(无参,函数体为空)
2.默认析构函数(无参,函数体为空)
3.默认拷贝构造函数,对属性进行值拷贝
构造函数调用规则如下:
如果用户定义有参构造函数,c++不在提供默认无参构造,但是会提供默认拷贝构造,
如果用户定义拷贝构造函数,C++不会再提供其他构造函数
#include<iostream>
using namespace std;
//1 创建一个类,c++会给每个类至少添加三个函数
class person
{
public:
//person()
//{
// cout << "构造函数" << endl;
//}
//有参构造函数
person(int a)
{
age = a;
cout << "有参构造函数" << endl;
}
//拷贝构造函数
//person(const person& p)
//{
//age = p.age;
//cout << "拷贝构造函数" << endl;
//将传入的人的所有属性,拷贝到他身上
//}
//析构函数
~person()
{
cout << "析构函数" << endl;
}
int age;
};
//1 创建一个类,c++会给每个类至少添加三个函数
//void test01()
//{
// person p;
// p.age = 18;
// person p2(p);
// cout << "p2年龄为" << p2.age<<endl;
//}
//2 如果写了有参构造函数,编译器就不再提供默认构造,依然提供拷贝构造★★★★★★★★★★★★★★★★★★★★★★★
// 如果写了拷贝构造函数,编译器就不提供其他的了。★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★
void test02()
{
person p(129);
person p2(p);
cout << "p2年龄为" << p2.age << endl;
}
int main() {
//test01();
test02();
system("pause");
return 0;
}
2.5 浅拷贝和深拷贝
浅拷贝:简单的赋值拷贝操作
深拷贝:在堆区重新申请空间,进行拷贝操作
#include<iostream>
using namespace std;
class person
{
public:
//构造函数
person()
{
cout << "构造函数" << endl;
}
//有参构造函数
person(int a, int height)
{
m_age = a;
m_height = new int(height);
cout << "youcan构造函数" << endl;
}
//之前没有写拷贝构造函数,就是系统默认的垃圾拷贝构造函数啊。
//自己实现拷贝构造函数,解决浅拷贝带来的问题
person(const person& p)
{
cout<<"拷贝构造函数调用,myself" << endl;
m_age = p.m_age;
//m_height = p.m_height; 编译器默认实现的就是这行代码 qiankaobei
//深拷贝操作
m_height = new int(*p.m_height); //从新申请一块内存 shenkaobei
}
//析构函数
~person()
{
//析构代码, 将堆区开辟的数据做释放操作
if (m_height != NULL)
{
delete m_height;
m_height = NULL;
}
cout << "析构函数" << endl;
}
int m_age;
int* m_height;
};
void test01()
{
person p1(18, 160);
cout << "p1的年龄为" <<p1.m_age<< "身高为" <<*p1.m_height<< endl;
person p2(p1); //浅拷贝??
cout << "p2的年龄为" << p2.m_age <<"身高为" << *p2.m_height<< endl;
}
int main() {
test01();
system("pause");
return 0;
}
2.6 初始化列表
作用:C++提供了初始化列表语法,用来初始化属性
语法:构造函数()∶属性1(值1) ,属性2(值2) …
#include<iostream>
using namespace std;
class person
{
public:
//传统初始化的操作
//person(int a, int b, int c)
//{
// m_a = a;
// m_b = b;
// m_c = c;
//}
//初始化列表初始化属性
person() : m_aa(10), m_bb(20), m_cc(30)
{
}
//初始化列表初始化属性,升华
person(int aa, int bb, int cc) : m_aaa(aa), m_bbb(bb), m_ccc(cc)
{
}
int m_a;
int m_b;
int m_c;
int m_aa;
int m_bb;
int m_cc;
int m_aaa;
int m_bbb;
int m_ccc;
};
void test01()
{
person p(10, 20, 30);
cout << "m_a" << p.m_a << endl;
cout << "m_b" << p.m_b << endl;
cout << "m_c" << p.m_c << endl;
}
void test02()
{
person p;
cout << "m_aa" << p.m_aa << endl;
cout << "m_bb" << p.m_bb << endl;
cout << "m_cc" << p.m_cc << endl;
}
void test03()
{
person p(99,88,55);
cout << "m_aa" << p.m_aaa << endl;
cout << "m_bb" << p.m_bbb << endl;
cout << "m_cc" << p.m_ccc << endl;
}
int main() {
test03();
system("pause");
return 0;
}
2.7 类对象作为类成员
C++类中的成员可以是另一个类的对象,我们称该成员为对象成员。
B类中有对象A作为成员,A为对象成员。
那么当创建B对象时,A与B的构造和析构的顺序是谁先谁后?
#include<iostream>
using namespace std;
//手机类
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;
}
//xingming
string m_name;
//phone
phone m_phone;
};
// 当其他的类对象作为本类的成员时候,构造时候先构造类对象,再构造自身,而析构呢???????
void test01()
{
person p("张三", "苹果max");
cout << p.m_name << "拿着" << p.m_phone.m_pname << endl;
}
int main() {
test01();
system("pause");
return 0;
}
2.8 静态成员
静态成员就是在成员变量和成员函数前加上关键字static,称为静态成员
静态成员分为:
静态成员变量 | 静态成员函数 |
---|---|
所有对象共享同一份数据。在编译阶段分配内存 | 所有对象共享同一个函数 |
类内声明,类外初始化· | 静态成员函数只能访问静态成员变量 |
2.8.1静态成员变量(1)
#include<iostream>
using namespace std;
//静态成员变量
class person
{
public:
//1 所有对象都共享同一份数据
static int m_a;
private:
static int m_b;
};
int person::m_a = 100;
int person::m_b = 200;
void test01()
{
person p;
cout<<p.m_a<<endl;
person p2;
p2.m_a = 200;
cout << p2.m_a << endl;
cout << p.m_a << endl;
}
void test02()
{
//静态成员变量 不属于某个对象 所有对象都共享同一份数据
//1.通过对象访问
person p;
cout <<p.m_a<<endl;
//2. 通过类名访问
cout << person::m_a << endl;
cout << person::m_a << endl;
}
int main() {
test01();
system("pause");
return 0;
}
2.8.2 静态成员变量(2)
#include<iostream>
using namespace std;
//静态成员函数
class person
{
public:
//1 所有对象都共享同一份数据
static void func()
{
m_a = 100; //静态成员可以访问 静态成员变量
//m_b = 200; //静态成员函数 不可以访问 非静态成员变量,无法区别到底是那个对象的m_b
cout << "static的调用" << endl;
}
static int m_a;
int m_b ;
private:
static void func2()
{
cout << "私有的static的调用" << endl;
}
};
int person::m_a = 100;
void test01()
{
//1.通过对象访问
person p;
p.func();
//2. 通过类名访问
person::func();
//person::func2(); //私有不可以访问 !!!!!!!!
}
int main() {
test01();
system("pause");
return 0;
}