封装是面向对象编程中的一个重要概念,它把对象的属性和操作(或服务)结合为一个独立的整体,并尽可能隐藏对象的内部实现细节。封装可以理解为一种信息隐藏技术,通过封装,对象的内部状态信息被隐藏在对象内部,只通过已定义的接口对外提供操作。
封装是面向对象编程中的一个重要概念,它把对象的属性和操作(或服务)结合为一个独立的整体,并尽可能隐藏对象的内部实现细节。封装可以理解为一种信息隐藏技术,通过封装,对象的内部状态信息被隐藏在对象内部,只通过已定义的接口对外提供操作。
![第五章丨C++编程宝典:快速上手、深入进阶、挑战高级技巧,助你成为编程达人](https://www.xiciw.com/wp-content/uploads/2024/01/2024012819012084.webp)
接上一张C++编程宝典 第四章丨C++编程宝典:快速上手、深入进阶、挑战高级技巧,助你成为编程达人 – 菜鸟资源 (xiciw.com)
这一章讲解封装
封装概述:
在面向对象编程中,封装是实现其他面向对象特性(如继承、多态)的基础。封装有以下几个关键点:
- 私有化:通过使用访问修饰符(如private),将对象的属性设置为私有,使得这些属性只能在对象的内部被访问和修改。
- 创建公共接口:为了提供对对象内部状态的访问和修改,需要创建公共的接口(如getter和setter方法),这些方法可以在类的外部被调用。
- 隐藏实现细节:通过封装,实现细节被隐藏在对象内部,使用者只需要关心对象提供的公共接口,而不必了解具体的实现细节。
封装的好处包括:
- 信息隐藏:通过封装,可以隐藏对象的内部实现细节,使得代码更安全、更易于维护。
- 提高代码可读性和可维护性:通过封装,将相关的变量和函数封装成一个对象,使得代码更加模块化、结构化。
- 增加代码的可扩展性:通过封装,可以在不改变对象外部接口的情况下,向对象添加新的属性和方法。
- 控制对数据的访问:通过封装,可以控制对对象的属性进行访问和修改,从而实现对数据的访问限制。
在Java中,封装通过关键字private、protected和public实现。private表示成员变量和方法只能在定义的类中被访问,具有类可见性;protected表示成员变量和方法可以被同一个包中的类访问,也可以被同一个项目不同包中的子类访问;public表示成员变量和方法可以被同一个项目中的所有类访问,具有最大的访问权限。
总之,封装是面向对象编程中的一个重要概念,它把对象的属性和操作组合在一起,并隐藏对象的内部实现细节。通过封装,可以提高代码的可读性、可维护性、安全性和可扩展性。
菜鸟精讲章节-开始
- 封装(Encapsulation)
3.1. 封装
3.1.1. 从struct说起
当单一变量无法完成描述需求的时候,结构体类型解决了这一问题。可以将多个类型打包成一体,形成新的类型。这是 c 语言中封装的概念。
但是,新类型并不包含,对数据类的操作。所的有操作都是通过函数的方式,去其进行封装。
struct Date
#include <iostream>
using namespace std;
struct Date
{
int year;
int month;
int day;
};
void init(Date &d)
{
cout<<"year,month,day:"<<endl;
cin>>d.year>>d.month>>d.day;
}
void print(Date & d)
{
cout<<"year month day"<<endl;
cout<<d.year<<":"<<d.month<<":"<<d.day<<endl;
}
bool isLeapYear(Date & d)
{
if((d.year%4==0&& d.year%100 != 0) || d.year%400 == 0)
return true;
else
return false;
}
int main()
{
Date d;
init(d);
print(d);
if(isLeapYear(d))
cout<<"leap year"<<endl;
else
cout<<"not leap year"<<endl;
return 0;
}
struct stack
#include <iostream>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
using namespace std;
struct Stack
{
int space[1024];
int top;
};
void init(Stack &s)
{
memset(s.space,0,sizeof(s.space));
s.top = 0;
}
bool isEmpty(Stack &s)
{
return s.top == 0;
}
bool isFull(Stack &s)
{
return s.top == 1024;
}
void push(Stack& s,int data)
{
s.space[s.top++] = data;
}
int pop(Stack &s)
{
return s.space[--s.top];
}
int main()
{
Stack s;
init(s);
if(!isFull(s))
push(s,10);
if(!isFull(s))
push(s,20);
if(!isFull(s))
push(s,30);
if(!isFull(s))
push(s,40);
if(!isFull(s))
push(s,50);
while(!isEmpty(s))
cout<<pop(s)<<endl;
return 0;
}
3.1.2. 封装的访问属性
![第五章丨C++编程宝典:快速上手、深入进阶、挑战高级技巧,助你成为编程达人](https://www.xiciw.com/wp-content/uploads/2024/01/2024012906320398.webp)
struct 中所有行为和属性都是 public 的(默认)。C++中的 class 可以指定行为和属性的访问方式。
封装,可以达到,对内开放数据,对外屏蔽数据,对外提供接口。达到了信息隐蔽的功能。
比如我们用 struct 封装的类,即知其接口,又可以直接访问其内部数据,这样却没有达到信息隐蔽的功效。而 class 则提供了这样的功能,屏蔽内部数据,对外开放接口。
3.1.3. 用class去封装带行为的类
class 封装的本质,在于将数据和行为,绑定在一起然后能过对象来完成操作。Date 类
#include <iostream>
using namespace std;
class Date
{
public:
void init(Date &d);
void print(Date & d);
bool isLeapYear(Date & d);
private:
int year;
int month;
int day;
};
void Date::init(Date &d)
{
cout<<"year,month,day:"<<endl;
cin>>d.year>>d.month>>d.day;
}
void Date::print(Date & d)
{
cout<<"year month day"<<endl;
cout<<d.year<<":"<<d.month<<":"<<d.day<<endl;
}
bool Date::isLeapYear(Date & d)
{
if((d.year%4==0&& d.year%100 != 0) || d.year%400 == 0)
return true;
else
return false;
}
int main()
{
Date d;
d.init(d);
d.print(d);
if(d.isLeapYear(d))
cout<<"leap year"<<endl;
else
cout<<"not leap year"<<endl;
return 0;
}
Date 类 访问自己的成员 可以不需要能过传引用的方
#include <iostream>
using namespace std;
class Date
{
public:
void init();
void print();
bool isLeapYear();
private:
int year;
int month;
int day;
};
void Date::init()
{
cout<<"year,month,day:"<<endl;
cin>>year>>month>>day;
}
void Date::print()
{
cout<<"year month day"<<endl;
cout<<year<<":"<<month<<":"<<day<<endl;
}
bool Date::isLeapYear()
{
if((year%4==0&& year%100 != 0) || year%400 == 0)
return true;
else
return false;
}
int main()
{
Date d;
d.init();
d.print();
if(d.isLeapYear())
cout<<"leap year"<<endl;
else
cout<<"not leap year"<<endl;
return 0;
}
Stack 类
#include <iostream>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
using namespace std;
class Stack
{
public:
void init();
bool isEmpty();
bool isFull();
void push(int data);
int pop();
private:
int space[1024];
int top;
};
void Stack::init()
{
memset(space,0,sizeof(space));
top = 0;
}
bool Stack::isEmpty()
{
return top == 0;
}
bool Stack::isFull()
{
return top == 1024;
}
void Stack::push(int data)
{
space[top++] = data;
}
int Stack::pop()
{
return space[--top];
}
int main()
{
Stack s;
s.init();
if(!s.isFull())
s.push(10);
if(!s.isFull())
s.push(20);
if(!s.isFull())
s.push(30);
if(!s.isFull())
s.push(40);
if(!s.isFull())
s.push(50);
while(!s.isEmpty())
cout<<s.pop()<<endl;
return 0;
}
3.2. 练习封装 list
3.2.1. 系统封装的list
#include <iostream>
#include <list>
using namespace std;
int main()
{
list<int> lint;
//增
lint.push_back(1);
lint.push_back(2);
lint.push_back(3);
lint.push_back(4);
//删
lint.remove(3);
//输出
list<int>::iterator litr;
for(litr = lint.begin(); litr != lint.end(); ++litr)
{
cout<<*litr<<endl;
}
//逆转
lint.reverse();
for(litr = lint.begin(); litr != lint.end(); ++litr)
{
cout<<*litr<<endl;
}
//改
for(litr = lint.begin(); litr != lint.end(); ++litr)
{
*litr = 100;
}
for(litr = lint.begin(); litr != lint.end(); ++litr)
{
cout<<*litr<<endl;
}
//清空
lint.clear();
for(litr = lint.begin(); litr != lint.end(); ++litr)
{
cout<<*litr<<endl;
}
return 0;
}
3.2.2. 自己的list
提示:
typedef struct node
{
int data; //数据域
struct node *next; //指针域
}Node;
class List
{
public:
void initList();
void insertList();
void deleteNode(Node * pfind);
Node * searchList(int find);
void sortList();
void destroy();
private:
Node * head;
};
- 类与对象(Class &&object)
4.1. stack 声明与定义
引入构造器实现 自定义 栈大
#include <iostream>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
using namespace std;
class Stack
{
public:
Stack(int size=1024);
~Stack();
void init();
bool isEmpty();
bool isFull();
void push(int data);
int pop();
private:
int* space;
int top;
};
Stack::Stack(int size)
{
space = new int[size];
top = 0;
}
Stack::~Stack()
{
delete []space;
}
//void Stack::init()
//{
// memset(space,0,sizeof(space));
// top = 0;
//}
bool Stack::isEmpty()
{
return top == 0;
}
bool Stack::isFull()
{
return top == 1024;
}
void Stack::push(int data)
{
space[top++] = data;
}
int Stack::pop()
{
return space[--top];
}
int main()
{
// Stack s;
Stack s(100);
// s.init();
if(!s.isFull())
s.push(10);
if(!s.isFull())
s.push(20);
if(!s.isFull())
s.push(30);
if(!s.isFull())
s.push(40);
if(!s.isFull())
s.push(50);
while(!s.isEmpty())
cout<<s.pop()<<endl;
return 0;
}
4.2. 构造器(Constructor)
4.2.1. 定义及意义
class 类名
{
类名(形式参数)
构造体
}
class A
{
A(形参)
{}
}
在类对象创建时,自动调用,完成类对象的初始化。尤其是动态堆内存的申请。
规则:
1 在对象创建时自动调用,完成初始化相关工作。
2 无返回值,与类名同,默认无参,可以重载,可默认参数。
3 一经实现,默认不复存在。
Stack::Stack(int size)
{
space = new int[size];
top = 0;
}
4.2.2. 参数初始化表
Stack::Stack(int size)
:space(new int[size]),top(0)
{
}
下面代码中有错误吗?
#include <iostream>
#include <string.h>
using namespace std;
class A
{
public:
A(char * ps)
:name(ps),len(strlen(name.c_str())){}
void dis()
{
cout<<len<<endl;
}
private:
int len;
string name;
};
int main()
{
A a("china");
a.dis();
return 0;
}
结论:初始化列表中的初始化顺序,与声明顺序有关,与前后赋值顺序无关。
4.3. 析造器(Destructor)
4.3.1. 对象销毁时期
1,栈对象离开其作用域。
2,堆对象被手动 delete.
4.3.2. 析构器的定义及意义
class 类名
{
~类名()
析造体
}
class A
{
~A()
{}
}
在类对像销毁时,自动调用,完成对象的销毁。尤其是类中己申请的堆内存的释放.
规则:
1,对象销毁时,自动调用。完成销毁的善后工作。
2,无返值 ,与类名同。无参。不可以重载与默认参数
Stack::~Stack()
{
delete []space;
}
4.3.3. 小结
析构函数的作用,并不是删除对象,而在对象销毁前完成的一些清理工作。
4.4. 多文件编程
通常我们将类的声明,放到.h 文件中去,而将实现放到.cpp 中去。
4.5. 拷贝构造(Copy contructor)
4.5.1. 拷贝构造的定义及意义
由己存在的对象,创建新对象。也就是说新对象,不由构造器来构造,而是由拷贝构造器来完成。拷贝构造器的格式是固定的。
class 类名
{
类名(const 类名 & another)
拷贝构造体
}
class A
{
A(const A & another)
{}
}
规则:
1 系统提供默认的拷贝构造器。一经实现,不复存在。
2 系统提供的时等位拷贝,也就是所谓的浅浅的拷贝。
3 要实现深拷贝,必须要自定义。
4.5.2. 拷贝构造发生的时机。
1,制作对象的副本。
2,以对象作为参数和返回值。
4.5.3. 深拷贝与浅拷贝
系统提供默认的拷贝构造器,一经定义不再提供。但系统提供的默认拷贝构造器是等
位拷贝,也就是通常意义上的浅拷贝。如果类中包含的数据元素全部在栈上,浅拷贝也可
以满足需求的。但如果堆上的数据,则会发生多次析构行为。
图示:
![第五章丨C++编程宝典:快速上手、深入进阶、挑战高级技巧,助你成为编程达人](https://www.xiciw.com/wp-content/uploads/2024/01/2024012907071179.webp)
#include <iostream>
#include <string.h>
using namespace std;
class A
{
public:
A(int d,char *p):data(d)
{
pd = new char[strlen(p)+1];
strcpy(pd,p);
}
~A()
{
delete[]pd;
}
A(const A& another)
{
pd = new char[strlen(another.pd)+1];
strcpy(pd,another.pd);
}
void dis()
{
cout<<data<<endl;
cout<<pd<<endl;
}
private:
int data;
char *pd;
};
int main()
{
// A a(20);
// a.dis();
// A b(a);
// b.dis();
// A c = b;
// c.dis();
A a(20,"china");
a.dis();
A b(a);
b.dis();
A c = b;
c.dis();
return 0;
}
本章完,请关注菜鸟资源技术C/C++教程精讲课程
生如夏花之绚烂,死如秋叶之静美