C++笔记 下
函数重载
满足条件:
1.同一个作用域下
2.函数名称相同
3.函数的参数类型不同或者个数不同或者顺序不同
可以让函数相同。提高函数复用性
函数的返回值类型不能重载
注意事项:
1.引用作为重载的条件
func(10);会调用:
void func(const int &a);
func(a);会调用:
void func(int &a);
2.函数重载碰到默认参数
类和对象
三大特征:封装,继承和多态
相同性质的对象抽象为类
封装
意义:
将属性和行为作为一个整体,表现生活中的事物
将属性和行为加以权限控制
封装的访问权限:
公共权限 public 类内可以访问,类外也可以
保护权限 protected 类内可以访问,类外不可以访问,子类可以访问
私有权限 private 类内可以访问,类外不可以访问,子类不能访问
struct和class区别
class默认的权限是私有
struct默认是公共
成员属性私有化
将所有成员设置为私有,可以自己控制读写权限、
对于写权限,我们可以检测数据的有效性
对象的初始化和清理
对象的常识化和清理是两个非常重要的安全问题
一个对象或者变量没有初始状态,对其使用的后果是未知的
同样的使用完一个对象或变量,没有及时清理,也会造成一定的安全问题
C++利用了构造和析构函数来解决上述问题,这两个函数将被编译器自动调用,完成对象的初始化和清理工作
我们不提供构造和析构,编译器可以提供的构造和析构函数是空实现
构造函数
主要作用于创建对象时为对象的成员属性赋值,构造函数由编译器自动调用,无须手动调用
1.没有返回值也不写void
2.函数名称与类名相同
3.构造函数可以有参数,因此可以发生
4.程序在调用对象时候会自动调用构造,无须手动调用,而且只会调用一次
析构函数
主要作用于对象销毁前系统自动调用,执行一些清理工作
1.没有返回值也不写void
2.函数名称与类名相同,在名称前加上符号~
3.析构函数不可以有参数,因此不可以发生重载
4.程序在对象销毁前会自动调用析构,无须手动调用,而且只会调用一次
#include<iostream> using namespace std; class Person { public: Person(){ cout <<"Person构造函数的调用"<<endl; } ~Person(){ cout <<"Person的析构函数的调用"<<endl; } }; void test01(){ Person p; } int main(){ test01(); return 0; }
test01中的Person是栈上面的数据
写在main函数中不会调用析构函数
函数的分类以及调用
按参数分为:有参构造和无参构造
按类型分为:普通构造和拷贝构造
三种调用方式:
括号法
显示法
隐式转换法
Person(int a){ } Person(const Person &p) //拷贝构造函数的方法 { age=p.age; } //括号法 void Person(){ • Person p1; • Person p2(10); //括号法调用有参构造函数 • Person p3(p2); //调用拷贝构造函数 }
调用默认构造函数时候不要加();
void func();和Person p1();形式一样,会被编译器理解为函数声明
//显示法 void Person(){ • Person p1; • Person p2=Person(10); Person p3=Person(p2); Person(10); //匿名对象 特点:当前执行结束后,会回收匿名对象 } //不要用拷贝构造函数初始化匿名对象 //隐式转换法 Person p4=10; //相当于写了Person p4=Person(10); Person p5=p4; //拷贝构造
拷贝构造函数调用时机
使用一个已经创建完毕的对象来初始化一个新对象
值传递的方式来给函数传值
以值方式返回局部对象
#include<iostream> using namespace std; class Person{ int M_age; 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; } }; void doWork(Person p){ } void test02(){ Person p; doWork(p); } int main(){ test02(); return 0; } //实参传给形参会调用拷贝构造函数,值传递会拷贝副本 #include<iostream> using namespace std; class Person{ int M_age; 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; } }; Person doWork2(){ Person p; return p; } void test03(){ Person p=doWork2(); } int main(){ test03(); return 0; }
构造函数的调用规则
默认情况下,C++会为一个类添加3个函数:
1.默认构造函数
2.默认析构函数
3.默认拷贝构造函数
如果用户定义了有参构造函数,C++不会提供无参构造函数,但是会提供默认拷贝构造
如果用户定义拷贝构造函数,C++不会提供其他构造函数
深拷贝与浅拷贝
浅拷贝:简单的赋值拷贝操作
深拷贝:在堆区重新申请空间,进行拷贝工作
析构代码,将堆区开辟的数据做释放操作
释放是先进后出,后面的先释放
浅拷贝的问题:堆区的问题重复释放
m_Height是一个指针
编译器默认的拷贝
m_Height=p.m_Height
深拷贝操作应该是
m_Height=new int(*p.m_Height); ~Person(){ • if(m_Height!=NULL){ • delete m_Height; • m_Height=NULL; • } }
有属性是堆区开辟的,一定要自己提供拷贝构造函数,防止浅拷贝带来的问题
初始化列表
Person():m_A(10),m_B(20),m_c(30){ } Person(int a,int b,int c):m_A(a),m_B(b),m_c(c){ }
类对象作为类成员
C++类中的成员可以是另一个类的对象,称该成员为对象成员
静态成员
静态成员变量
所有对象共享一份数据
在编译阶段分配内存
类内声明,类外初始化
class Person { public: • static int m_A; }; int Person::m_A=100
1.通过对象进行访问
2.通过类名进行访问
静态成员变量也是有访问权限的
静态成员函数
void test01(){ • //1.通过对象访问 • Person p; • p.func(); • 2.通过类名访问 • Person::func(); }
静态成员函数可以访问静态成员变量
静态成员函数不可以访问非静态成员变量
C++对象模型和this指针
空对象占用的内存空间是1
C++编译器会给每个空对象也分配一个字节空间,是为了区分空对象占内存的位置
每个空对象也有一个独一无二的的内存地址
静态的成员变量不属于类的对象上面
非静态成员函数不属于类的对象上
只有非静态的成员变量属于类的对象上
this指针的用途
C++的成员变量和成员函数是分开储存的
this指针指向被调用的成员函数所属的对象
this指针是隐含与每一个非静态成员函数的一种指针
this指针不需要定义,直接使用即可
当形参和成员变量同名时,可用this指针来区分
在类的非静态成员函数中返回对象本身,可使用return *this
this->age=age;
return *this;
Person&
空指针访问成员函数
C++空指针也是可以调用成员函数,但是也要注意有没有用到this指针
如果用到this指针。需要加以判断代码的健壮性
#include<iostream> using namespace std; class Person{ public: void showClassName(){ cout <<"Person"<<endl; } void showAge(){ cout <<"Age="<<m_Age<<endl; } int m_Age; }; void test01(){ Person *p=NULL; p->showClassName(); //不会报错 p->showAge(); //报错 } int main(){ test01(); return 0; } #include<iostream> using namespace std; class Person{ public: void showClassName(){ cout <<"Person"<<endl; } void showAge(){ if(this==NULL) return; cout <<"Age="<<m_Age<<endl; } int m_Age; }; void test01(){ Person *p=NULL; p->showClassName(); p->showAge(); } int main(){ test01(); return 0; }
const修饰成员函数
常函数
成员函数加const后我们称这个函数为常函数
常函数内不可以修改成员属性
成员属性声明时加关键字mutable,在常函数中依然可以修改
常对象
声明对象前加const称该对象为常对象
常对象只能调用常函数
void showPerson()const { • m_A=100; }
this指针的本质是指针常量,指针的指向是不能修改的
友员
关键字 friend
友元的三种实现
全局函数做友元
类做友元
成员函数做友元