面向对象编程.封装

程序=数据结构+算法
主流的语言基本上都支持面向对象的。面向对象编程(OOP)
宏观上是面向对象,微观(细节)是面向过程
创建对象 利用对象与对象之间的相互作用解决问题
面向对象的三大特征:封装、继承、多态。

定义类(封装)
类是对对象的抽象及概括,对象是类的具体化和实例化。类是一个泛化的过程,对象是一个具体化的过程
类是一个抽象的概念,对象是个具体存在的事物。
创建类的语法
class 类名{};
class Stu{};//创建一个类,Stu是类名。class是定义类的关键字,和struct基本相同。如果里面什么都没有,就是个空类。空类sizeof=1。
类里面的变量 属性 成员变量。把对象的特征抽象为属性(成员变量)。成员变量用来描述一类事物的特征。
类里面的函数 成员函数,把对象共同的行为抽象为函数。成员方法 用来描述一类事物的行为
创建对象的过程其实是实例化对象的过程。类名 变量名;
Stu s;//实例化对象 //Stu s1={110,“zf”,30,80};//class中私有的成员不能这样初始化
封装 访问控制属性 默认是私有
public :公开的 类里面和类外面可以直接访问
private :私有的 只允许在类里面访问 友元
protected :保护的 只允许在本类和子类中访问
创建对象并初始化成员
Stu{public:。。。};//设为公开的 ={};
Stu{int id; string name; public: void init(int id1,string name1){id=id1; name=name1; } }; s.init(110,“zf”);//函数,给属性赋值
构造函数 class 类名{ //类名(形参列表){构造函数体}}; //1、构造函数没有返回值类型,2、构造函数名和类名相同
3、在实例化对象时,会自动调用构造函数。4、一般在构造函数里会进行初始化成员变量。
5、一个类如果没有构造函数,编译器会自动生成一个无参的空构造函数。默认生成的构造函数不会改变基本类型成员,但会调用类类型的无参构造函数
public: Stu(int n,string a){id=n; name=a;} Stu s1(110,“zf”);//6、构造函数可以重载 一般来说会手动提供无参构造函数
class和struct的区别:
class类里默认访问控制属性都是私有的,struct里默认访问控制属性都是公开的

对象与属性和函数
在成员函数中可以直接访问成员属性,也可以调用其他成员函数。
在类外面只能访问public的属性和方法,而且必须 对象.属性 对象.函数名(参数);

对象的构建过程
先分配内存 -> 调用构造函数(但没有执行) -> 调用类类型成员的构造函数进行构造成员 -> 执行构造函数体

栈和堆 对象
Circle c; //创建对象c,调用无参构造函数Circle()
Circle cir();//这是声明了一个返回值为Circle的函数,cir是函数,不是Circle对象。
new会自动调用构造函数:
Circle *pc1=new Circle;
Circle *pc2=new Circle(); //都是调用构造函数,创建对象
匿名对象 :类名(实参列表);Circle(2,2,1);

初始化列表
在构造函数里可以通过初始化列表的方式来初始化成员属性
class 类名{ 类名(形参列表):成员属性(给参数) }; public: Point(double x,double y):x(x1),y(y1){} c(x,y)调用Point类的构造参数
1、对类类型成员会自动在初始化列表中调用无参的构造函数,在构造体函数里其实只能对它赋值
2、在初始化列表中调用指定的构造函数来初始化类类型的成员变量,任何一个构造函数都会调用类类型的无参构造函数
3、对于常量成员和引用成员必须通过初始化列表的形式来进行初始化 const int x; int& r; 需要(int m,int& n):x(m),r(n){}
4、成员初始化的顺序与初始化列表的顺序无关,只与成员声明的先后顺序有关。
只有构造函数才有初始化列表

this
成员函数中,局部变量和成员变量同名时,如果直接使用访问的是局部变量,局部变量会隐藏成员变量。用初始化列表就可以正常初始化
this->name;//this是一个指针,在类的成员函数和构造函数中,都有一个隐藏的this指针
this指针的类型就是当前类类型的指针。在构造函数中,this指针指向正在被构造的对象;在成员方法中,指向正在调用该成员方法的对象。<-
1、区分成员变量和局部变量 this->name:成员变量 ;name:局部变量。
2、作为参数 3、作为返回值
在成员函数内部优先访问局部变量。::调用全局的函数。没有同名函数可以省略::。
publuc: Integer &inc{++data; return * this;} Integer i; i.inc().inc().inc();
callFunc(* this);//要先声明类和函数
C++编译时会把类型和函数进行检查,所以使用到的类和函数应该先声明,后使用
void fun(类名 o){}//如果要访问o的成员,则这个类必须先定义
常对象:有const修饰的对象
常函数:在成员函数的形参列表后面添加const的函数 void show()const{} const修饰的是*this
常对象只能调用常函数,对于普通对象,优先调用非常函数。成员的常函数和非常函数可以构成重载。 <-
常函数里不能对属性值进行修改,除非用mutable修饰的属性。mutable修饰的属性即使是常对象也能修改
常函数只能调用常函数,不能调用普通的成员函数,const_cast<Point *>(this) 去掉这个常函数的常属性。

Stu s(321); Stu s=123;//可以调用构造函数初始化。 如果一个A类提供一个B类型单参的构造函数,那么任何B类型的对象都可以隐式转换成A类型的
构造函数前加explicit,就不能隐式转换,但还能显式构造。Stu s(string(“name”));

析构函数
每个对象在消亡时会自动调用析构函数。函数中的局部变量,函数返回时。调用delete释放new对象内存时。
编译器会自动给每个类生成一个默认的析构函数,
class 类名{~类名(){} } 析构函数名与类名相同,在类名前有一个~。析构函数没有返回值类型。析构函数没有任何参数,不能重载。
析构函数一般用于回收对象消亡时的资源。在构造函数中申请了动态内存,则需要在析构函数中释放动态内存。
析构函数中会自动调用类类型成员的析构函数。
析构函数默认执行顺序: 调用析构函数 -> 析构函数体 -> 按照类类型成员的声明顺序的相反顺序依次调用类类型成员的析构函数

拷贝构造函数
编译器会自动生成拷贝构造函数 class 类名{ 类名(const 类名& o){} } 一定要有&,const某些时候可以省略
默认生成的拷贝构造函数的实现 是按照字节复制的形式进行拷贝
哪些时候会调用拷贝构造函数 :用已经实例化的对象来构造一个新的对象 Emp e2(e1); Emp e3=e1; func(Emp e){} func(e1);//函数传递时,
调用引用参数bar(Emp &e){}不会拷贝构造 func(Emp());//匿名对象作为实参,无参构造,没有拷贝构造
Emp e4=func();//有可能会调用拷贝构造,返回一个全局的 或者 * this 或者 引用对象时,会调用拷贝构造。返回匿名对象 或者 函数内声明的对象时,不会调用
默认的拷贝构造函数都是进行字节复制,即浅拷贝。如果需要实现深拷贝则需要直接手动实现。
深拷贝:对于指针类型的成员变量,不是拷贝指针本身的值,而是拷贝指针指向的数据。 Pointer(const Pointer &pt){p=new int(*(pt.p)) }//实现深拷贝构造函数
默认的拷贝构造函数会调用类类型成员的拷贝构造函数,手动实现时需要在初始化列表中

拷贝赋值运算函数 =
A& operator=(const A& a){} //函数名operator=
1、当两个对象都已实例化之后,把一个对象的值付给另外一个对象。2、 编译器会自动生成赋值函数,实现是浅拷贝。3、如果需要实现深拷贝则需要手动实现。

Stu& operator=(const Stu& s){
	no=s.no; name=s.nam; score=s.score; 
}

Pointer& operator=(const Pointer& pt){//拷贝赋值,深拷贝
	*p=*pt.p; 
}

C(const C &c):a(c.a),b(c.b){} //拷贝构造  

C& operator=(const C& c){//拷贝赋值
	a.operate=(c.a); b.operator=(c.b);
}

静态成员和静态函数
static修饰的属性 类属性 ;static修饰的函数 类函数 class M{static int y;}//每个对象共享同一个
类属性-静态属性,属于类而非对象。类属性要在类外进行初始化。int M::y=0; public的话,静态属性可以通过类名::静态属性名(M::y)访问
静态属性是加了类属性的全局变量(访问控制属性,类名:: ),依然可以通过 对象.静态属性 的方式访问
类函数-静态函数,属于类而非对象。可以直接通过 类名::静态函数(实参) 的方式调用。
静态函数中不可以访问成员变量和调用成员函数。静态函数中没有隐藏的this指针,可以通过 对象.静态函数(实参)的方式调用。
但可以访问静态属性,调用静态函数(访问类所有成员共享的内容)。
对象中不会存储静态属性。

单例模式
创建一个类 这个类只能生成一个对象
构造函数全部私有。提供获得类的实例,没对象不能调用,所以只能声明静态函数

成员指针:成员属性指针,成员函数指针,静态属性指针,静态函数指针
1成员属性指针:成员属性类型 类名::*变量名=&类名::成员属性; int Stu::*pno=&Stu::no;
直接对象解引用:对象.*成员属性指针; s.*pno;
间接成员解引用:对象->*成员属性指针; Stu *ps=new Stu(…)s; ps->*pno
2成员函数指针:成员函数返回值类型 (类名::*函数指针名)(成员参数列表); 成员函数返回值类型 (类名::*函数指针名)(成员参数列表)=&类名::成员函数名
解引用:(对象.*成员函数指针名)(实参列表); (对象指针->*成员函数指针民)(实参列表); void (Stu::*pf)(void)=&Stu::show; (s.pf)();//==s.show();
3对于静态属性的指针和普通指针是一样的。只是在去静态属性的地址时需要 &类名::静态属性; int
pi=&Stu::no;
4静态函数指针和普通函数指针一样。只是在去静态函数的地址时需要 &类名::静态函数; void(*psf)()=Stu::print; //&有没有都可以

运算符重载 3+4i
class Comples{ double r;//实部 double v;//虚部}
Complex operate+(const Complex &c){return Complex(r+c.r,v+c.v);}//重载加法运算符
运算符的重载方式
1、成员方式重载:X.operater*();//单目 X.operater*(M);//双目
2、友元方式重载:operater*(M);//单目 operater*(M,N);//双目 如果用两种方式实现,默认选择成员方式实现,c=c1+c2;
可以显式调用运算符重载的函数 X.operator*(); operater*(M);//单 X.operator*(M); operater*(M,N);//双
Complex& operate+=(const Complex &c){x+=c.x; y+=c.y; return *this;};//成员方式实现+=

友元 friend
在全局函数中访问类的私有属性。在类里声明friend。友元函数不是成员函数
在实现类时可以声明全局函数为此类的友元函数,那么在友元函数中可以访问该类的私有属性。也可以在类里实现函数。
友元类:在一个类中可以声明另一个类为友元类,那么在友元类中可以访问该类的私有属性和函数。
友元类的声明是单向的 class EMP{friend class Manager;}//在Manager里可以访问EMP的私有属性和函数,但EMP不能访问Manager的私有属性
friend Complex& operator-=(Complex &c1,const Complex &c2){c1.x-=c2.x; c1.y-=c2.y; return c1;}//友元方式实现+=

输入输出运算符<<>>只能以友元的方式重载 第一个操作数不是本类的类型对象 cout是ostream类型的对象

对于需要重载自增减运算符 通过哑元来区分前后+±-。

class X{ 
	X& operator++(){++data; return *this}//前加加 
	X operator++(int){int d=data; data++; return X(d);}//后加加 
};

[] 一般来说要提供 常函数版本 和 非常函数版本

class X{
	int& operator[](size_t index){return vect[index]} 
	const int& operator[]const(size_t index){return vect[index]} 
};

() 重载了()的类实例化出来的对象称为 函数对象,因为该对象可以像函数调用一样使用
void& operator()(){}

new delete

 class A{
 	static void* operator new(size_t size){
 		return malloc(size);
 	} static void operator(void*p){
 	free(p);
 	} 
 }

重载类型运算符 从源类型转换为目标类型 :
如果目标类型是基本类型,源类型是类类型,则可以在源类型中重载目标类型的运算符函数 类->基本
如果目标类型是类类型,源类型是基本数据类型,则可以在目标类型中添加一个源类型的单参构造函数 基本->类
如果目标类型和源类型都是类类型,则可以在源类型中重载目标类型的运算符 或者 在目标类型中添加一个源类型的单参构造函数 A类->B类
A–>B class A{ operater B(){return B();}};//重载B类型运算符 class B{ B(const A& a){} };
如果目标类型和源类型都是基础数据类型,除非本身支持或强制转换,别无他法

运算符重载建议: 1、不是所有运算符都能重载,不能重载的有::、?:、.*、sizeof、typeid
2、不是所有运算符都能用友元的方式重载,只能以成员方式重载的运算符:=、[]、()、-> 。 只能以友元方式重载 :<< >>
3、不能创建新的运算符。 4、建议运算符的重载保持其本身的含义

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值