c语言封装
属性和行为分开处理了,没有严格的类型检测,而c++不会。
c++封装
struct 和 class是一个意思,唯一的不同,默认权限s是public,c是private。
建议成员变量都设置为私有
const不能添加到函数的原因
成员函数可以调用私有成员,此时传入一个类就代表着你可以调用它的成员函数,而c++规定只有在类里面的成员函数才能调用私有成员,因此此时不能加const,因为加了也没有意义。
分文件编写
1.头文件加上.h文件,里面写类的声明
2.在源文件里加一个.cpp,写累的成员函数的实现,注意:函数要加上作用域
3.在main()函数文件中,写入头文件
注意:只能用双引号
对象的构造和析构
拷贝构造不能初始化匿名对象,编译器会认为你写的是对象的声明。
拷贝构造函数的调用时机
person(const person& p);//只能这么写
person(const person p);//这么写是错的,因为这样写为值传递,值传递就会再
//用一个拷贝构造,会无限循环下去。
1.用已经创建好的对象初始化新的对象
2.以值传递的方式给函数参数传值
void dowork(person c1)//相当于person c1 = person(c);
{}//此时会调用拷贝构造函数
main()
{
person c;
dowork(c);
}
3.以值方式返回局部对象
person dowork()
{
person p;
return p;
}
main()
{
person p1 = dowork();
}
release下优化代码,是编译器优化的,与debug运行的状况不同
系统默认给一个类提供三个函数 默认构造,拷贝构造,析构函数(其实是4个,还有一个=)
构造函数的调用规则
1.当我们提供了有参的构造函数,那么系统就不会再给我们提供默认构造函数了,但是系统会提供默认的拷贝构造函数,对类中非静态成员进行简单的值拷贝。
2.当我们提供了拷贝构造函数,系统就不会提供其他构造函数了。(自己写)
深拷贝浅拷贝
浅拷贝:
详见c++基础知识总结。
深拷贝:
自己写拷贝构造函数,分配内存
初始化列表
public:
person(int a,int b,int c):ma(a),mb(b),mc(c)
{}//用于p1
person():ma(10),mb(10),mc(10)
{}//用于p2
//利用初始化列表初始化数据
int ma;
int mb;
int mc;
main()
{
person p1(10,10,10);
person p2;
}
类对象作为成员
构造的顺序,现将类对象一一构造,然后构造自己,析构就会先析构自己。
excplicit关键字
动态分配内存
person *array = new person[10];//堆区通过new开辟数组一定会调用默认构造函数,所以一定要提供默认构造
person array2[10] = {person(1),person(2),....};//在栈上开辟数组,可以指定有参构造
//释放数组,加中括号,会寻找“数组大小记录”,从而清楚应该调用几次析构
delete [] array;
静态成员变量
在类外初始化的主要原因是可以通过类名访问静态变量
int person::s = 10;
main()
{
cout << person::s <<endl;
}
静态成员函数
属于一个类,可以通过类名访问,不可以访问普通成员变量,静态成员函数与静态成员变量相同都是有访问权限的。
单例模式
一个类只有一个实例对象,实例不需要自己释放
//单例模式案例-主席案例
class ChairMan
{
//构造函数进行私有化
private:
ChairMan(){}//创建之后就访问不了了,因为对象也是私有的
static ChairMan * SingleMan;//对象私有化,通过指针维护
ChairMan(const ChairMan& c){};//拷贝构造函数也私有化
public:
//提供方法访问
static ChairMan* get(){
return SingleMan;
}
}
ChairMan * ChairMan::SingleMan = new ChairMan;//在编译时就完成了初始化
main()
{
ChairMan* m1 = ChairMan::get();//只能够访问,不能够修改,没有权限
}
/*打印机案例*/
class printer
{
private:
printer(){};
printer(const printer& p1){};
static printer* p;
public:
static printer* get()
{
return p;
}
void printest{};
}
printer* printer::p = new printer;
main()
{
printer* p2 = printer::get();
p2->printest();
}
成员变量和成员函数分开存储
class里面的成员函数其实也不是在类里面的。
空类的大小为1,每个实例的对象都有独一无二的地址,char去维护这个地址,所以大小为1。
只有非静态成员变量才属于对象。
通过this指针区分到底是哪个成员函数。
this指针指向被调用的成员函数所属的对象,this指针永远指向当前的对象
void func(person * this){}//编译器会偷偷加入一个指针
链式编程。(上图的返回引用就是返回本体)
空指针访问成员函数
person* p = NULL;
p->show();//如果show函数里面不会用到this指针就不会宕机,用到了就会
//如何处理
void show()
{
if(this == NULL)
return;
}
const修饰成员函数
void func() const;//常函数不允许修改指针指向的值
mutable int a;//就算是常函数,也可以修改
常对象
const person p;
常对象不可以调用普通成员函数,防止普通成员函数改变常对象里面数据成员的属性。只能调用常函数。
友元
目的访问类中的私有成员。
全局函数做友元
在类中写friend + 函数声明
让整个类做友元类
friend class + 类名
让成员函数做友元函数
强化训练数组类的封装
//array.h
#pragma once
#include <iostream>
using namespace std;
class array
{
public:
array();//默认构造
array(int capacity);//有参构造
array(const array& a);//拷贝构造
~array();
void push_back(int val);
int getdata(int index);
void setdata(int index,int val);
private
int* parray;//指向真正存储数据的指针
int size;//数组大小
int Capacity;//数组容量
};
#include "array.h"
array::array(){
this->Capacity = 100;
this->size = 0;
this->parray = new int[this->Capacity];
}
array::array(int capacity){
this->Capacity = capacity;
this->size = 0;
this->parray = new int[this->Capacity];
}
array::array(const array& a){
this->parray = new int[a.Capacity];
this->size = a.size;
this->Capacity = a.Capacity;
for(int i = 0; i < a.size; i++){
this->parray[i] = a.parray[i];
}
}
array::~array(){
if(this->parray != NULL){
delete [] this->parray;
this->parray = NULL;
}
}
void array::push_back(int val){
this->parray[this->size] = val;
this->size++;
}
int array::getdata(int index){
return this->parray[index];
}
void array::setdata(int index,int val){
this->parray[index] = val;
}