IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> C++知识库 -> C++ 类和对象(封装和对象的初始化和清理) -> 正文阅读

[C++知识库]C++ 类和对象(封装和对象的初始化和清理)

1.封装

1.1封装的意义

封装是C++面向对象三大特性之一。

意义:

1.将属性和行为作为一个整体,表现生活中的事物。

2.将属性和行为加以权限控制。

(类中的属性和行为统称成员,属性又叫成员属性,成员变量。行为又叫成员函数,成员方法)

意义1.

设计类时,将属性和行为写在一起,表现事物。

const double PI=3.14;
class Circle?
{
? ? //访问权限:公共权限?
? ? public:
?? ?// 属性:半径
?? ?int m_r;?
?? ?//行为:获取半径?
? ? double zhouchang()
? ? {
? ? ?? ?return 2 * PI * m_r;
?? ?}
? ?
};

int main ()
{
?? ?//实例化(通过一个类,创建一个对象的过程)?
?? ?Circle cl;//这个圆就是具体的对象?
?? ?cl.m_r =10;
?? ?cout<<"圆的周长是: "<<cl.zhouchang() <<endl;
?? ?return 0;?
}

意义2.

类在设计时,可以把属性和行为放在不同的权限下,加以控制。

访问权限有三种:

1.public? ? ? ? ?公共权限

2.protected? ?保护权限

3.private? ? ? ? 私有权限

在类内,都可以访问,在类外,1.可以访问,2.3.不可以访问.(2.3.区别与继承有关,相对来说,3的控制力度最大)

1.2 struct与class的区别

struct默认权限是公共;

class默认权限是私有。

在class中,如果不写public等权限词,默认private,为私有。

2.对象的初始化和清理

像生活中电子产品的出厂设置,和销毁前清空数据的设置

2.1构造函数和析构函数

构造函数就是初始化,析构函数就是清理。这两个函数会被编译器自动调用,我们不写这俩函数,编译器也会提供。

构造函数:主要作用于创建对象时为对象的成员属性赋值,构造函数由编译器自动调用,无需手动调用。

析构函数:主要用于对象销毁前系统自动调用,执行前一些清理工作。

构造函数语法:类名(){}

1.没有返回值也不写void

2.函数名称与类名相同;

3.构造函数可以有函数,因此可以发生重载;

4.程序在调用对象时候会自动调用,无需手动调用而且只会调用一次。

析构函数语法:~类名(){}

1.没有返回值也不写void

2.函数名称与类名相同,在函数名称前加 ~;

3.构造函数不可以有函数,因此不可以发生重载;

4.程序在销毁对象时候会自动调用,无需手动调用而且只会调用一次。

class person
{
public:
?? ?//1.构造函数?
?? ?person()
?? ?{
?? ??? ?cout<<"构造函数的调用"<<endl;
?? ?}
?? ?//2.析构函数
?? ?~person()
?? ?{
?? ??? ?cout<<"person的析构函数"<<endl;?
?? ? }?
};

2.2构造函数的分类及调用

两种分类方式:

按参数分:有参构造和无参构造

按类型分:普通构造和拷贝构造

三种调用方式:

括号法

显示法

隐式转换法?

#include<iostream>
#include<string>
using namespace std;

class person
{
public:
?? ?//1.构造函数?
?? ?person()//无参构造函数又叫默认构造函数?
?? ?{
?? ??? ?cout<<"无参构造函数的调用"<<endl;
?? ?}
?? ?person(int a)
?? ?{
?? ??? ?age=a;
?? ??? ?cout<<"有参构造函数"<<endl;?
?? ?}
?? ?person(const person &p)
?? ?{
?? ??? ?age=p.age ;
?? ??? ?cout<<"拷贝构造"<<endl;?
?? ?}??
?? ?
?? ?//2.析构函数
?? ?~person()
?? ?{
?? ??? ?cout<<"person的析构函数"<<endl;?
?? ? }?
?? ??
?? ? int age;
};

//构造和析构都是必须有的 实现,如果我们自己不提供,编译器会提供一个空实现的构造和析构?
void test01()
{
?? ?//括号法?
?? ?person p1;//默认构造函数调用
?? ?person p2(10);//有参 构造函数调用
?? ?person p3(p2);//拷贝构造函数调用
?? ?//注意事项1:
?? ?//调用默认构造函数时,不要加()
?? ?//因为加()后,编译器会认为这是函数声明,不会认为在创建对象?
?? ??

?? ?//显示法?
?? ?person p1;
?? ?person p2=person(10);//有参构造
?? ?person p3=person(p2);//拷贝构造
?? ?
//?? ?person(10);//匿名对象 特点:当前行执行结束后 ,系统会立即回收匿名对象;?
?? ??
?? ?//注意事项2;
?? ?//不要利用拷贝构造函数来初始化匿名对象,编译器会认为这是声明对象,造成重定义?
?? ?//person(p3);
?? ?
?? ??
?? ?//隐式转换法?
?? ?person p4=10;//相当于 person p4=person (10) ?有参构造
?? ?person p5=p4;//拷贝构造?person p5=person(p4)
}
?int main ()
?{
?? ?test01();
?? ?
?? ?system("pause");
?? ?return 0; ??
?}

2.3拷贝构造函数调用时机

三种情况:

1.使用一个已经创建完毕的对象来初始化一个新对象?

2.值传递的方式给函数参数传值

3.值方式返回局部对象

class person
{
public:
?? ?//1.构造函数?
?? ?person()//无参构造函数又叫默认构造函数?
?? ?{
?? ??? ?cout<<"person的默认构造函数调用"<<endl;
?? ?}
?? ?person(int a)
?? ?{
?? ??? ?age=a;
?? ??? ?cout<<"person的有参构造函数"<<endl;?
?? ?}
?? ?person(const person &p)
?? ?{
?? ??? ?age=p.age ;
?? ??? ?cout<<"penson的拷贝构造函数"<<endl;?
?? ?}
?? ?
?? ?//2.析构函数
?? ?~person()
?? ?{
?? ??? ?cout<<"person的析构函数"<<endl;?
?? ? }?
?? ??
?? ? int age;
};

//使用一个已经创建完毕的对象来初始化一个新对象?
void test01()
{
?? ?
?? ?person p1(20);
?? ?person p2(p1);
?? ?
?}?

//值传递的方式给函数参数传值
void dowork(person p)
{
?? ?
}

void test02()
{
?? ?person p;
?? ?dowork(p);
?}?
?
?//值方式返回局部对象
person dowork2()
{
??? ?person p1;
??? ?cout<<(int*)&p1<<endl;
??? ?return p1;
}?
void test03()
{
?? ?person p=dowork2();
?? ?cout<<(int*)&p<<endl;
}

2.4拷贝构造函数调用规则

1、默认情况下,创建一个类,编译器会给每一个类至少添加3个函数

默认构造(空实现:函数里没代码)

析构函数(空实现)

拷贝构造 (值拷贝)

2、如果我们写了有参构造函数,编译器就不再提供默认构造,依然提供拷贝构造。

如果我们写了拷贝构造函数,编译器也不会再提供其他普通构造函数。

2.5深拷贝与浅拷贝

class person
{
public:
?? ?person(int age,int height)
?? ?{
?? ??? ?m_age=age;
?? ??? ?m_height=new int(height);
?? ??? ?cout<<"有参构造函数" <<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 <<"析构函数"<<endl;?
?? ?}
?? ?int m_age;
?? ?int *m_height;
};

void test()
{
?? ?person p1(18,180);

?? ?cout << "年龄 : "<<p1.m_age <<" 身高 : "<<*p1.m_height <<endl;?
?? ?
?? ?person p2(p1);

?? ?cout << "年龄 : "<<p2.m_age <<" 身高 : "<<*p2.m_height <<endl; ?? ?
}

当用编译器提供的拷贝函数时,就是浅拷贝。如上有参构造函数中,m_height 是用new在堆区开辟的数据.需要在析构函数里手动释放m_height;如果用浅拷贝,p1执行完后会用析构函数释放m_height。后面拷贝函数p2执行完后会再次释放m_height。造成重复释放,出现错误。

这时需要深拷贝,开辟一个新的new数据,这样p2释放new数据时,不会重复释放。

2.6初始化列表

语法:构造函数?():属性1(值1),属性2(值2)...{}

class person
{
public:
?? ?//传统初始化操作?
//?? ?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)
?? ?{
?? ??? ?
?? ?}?
?? ??
?? ?int m_a;
?? ?int m_b;
?? ?int m_c;
};

void test01()
{

?? ?person p(30,20,10);
?? ?cout << "m_a= "<< p.m_a ?<<endl;
?? ?cout << "m_b= "<< p.m_b ?<<endl;
?? ?cout << "m_c= "<< p.m_c ?<<endl;
?? ?
}
??

2.7类对象作为类的成员

c++中类的成员可以是另一个类的对象,称为对象成员

class? A? {}

class? B?

{

? ? ? ? ?A? ?a;

}?

B类中有对象A作为成员,A称为对象成员.

2.8静态成员

静态成员就是在成员函数和成员变量前面加入static关键字,称为静态成员

静态成员分为:

静态成员变量:

1.所有对象共享同一份数据

2.在编译阶段分配内存

3.类内声明,类外初始化

静态成员函数:

1.所有对象共享同一函数

2.静态成员函数只能访问静态成员变量

class person
{
?? ?public:
?? ??? ?//静态成员函数?
?? ??? ?static void fun()
?? ??? ?{
?? ??? ??? ?m_A=100;//静态变量被共享?
?? ??? ??? ?m_B=200;//静态成员函数只能访问静态成员变量,所以函数里加上m_B会报错?
?? ??? ??? ?//因为无法区分m_B是那个对象的m_B?
?? ??? ??? ?cout <<"static void fun 调用"<<endl;
?? ??? ?}
?? ??? ?
?? ??? ?static int m_A;//静态成员变量 (必须在类内声明,再在类外初始化一下 )
?? ??? ?int m_B;//非静态成员变量?
?? ??? ?
} ;

?? ?int person::m_A =0;?
//所有对象共享同一个函数?
//两种访问方式?
void test1()
{
?? ?//1.通过对象访问
?? ?person p;
?? ?p.fun() ;
?? ?//2.通过类名访问
?? ?person :: fun()?
}

注意:如果在私有权限里声明静态成员函数则在类外无法访问

  C++知识库 最新文章
【C++】友元、嵌套类、异常、RTTI、类型转换
通讯录的思路与实现(C语言)
C++PrimerPlus 第七章 函数-C++的编程模块(
Problem C: 算法9-9~9-12:平衡二叉树的基本
MSVC C++ UTF-8编程
C++进阶 多态原理
简单string类c++实现
我的年度总结
【C语言】以深厚地基筑伟岸高楼-基础篇(六
c语言常见错误合集
上一篇文章      下一篇文章      查看所有文章
加:2022-03-13 21:33:09  更:2022-03-13 21:34:54 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/27 22:50:14-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码