C++(面向对象封装、继承、多态)
一、封装
封装本身是围绕着类进行的:在类中写各种各样的函数
1、类
在C++中创建类的函数有两个,分别是struct 和 class
struct 和 class 创建的叫类,使用 类 定义的变量叫做 对象,类中的变量叫做 成员变量
1)类 中对象的访问权限
piblic:公开权限 在类 内部,外部均可访问
protected:受保护权限 在类 内部可以访问,外部不可访问
private:私有权限 在类 内部可以访问,外部不可访问
目前来说 private 和 protected 这两个权限没有区别
private 和 public 具体使用
根据 c++ 标准委员会的要求(人为规定):没有特殊需求的时候,
所有的成员属性(变量),都放在private里面,所有成员方法(函数) ,都放在public里面
2)内部访问和外部访问
外部访问:
既不在类的作用域中访问成员属性,并且在访问的时候,前面也没有加上 作用域:: 运算符,都属于外部访问
内部访问:
和外部访问相反,只要在类的作用域里面,或者访问的时候,前面有 作用域::运算符,都属于内部访问
3)struct 和 class 的区别
创建类:
struct 创建的类,中的参数,默认是piblic(公开权限)
class 创建的类,中的参数,默认是private(私有权限)
初始化类:
class 不允许直接使用 {} 形式进行初始化 (如果想要使用{} 初始化,需要额外操作)
4)类 的初始化方式
类 的初始化要通过 构造函数 初始化
2、构造函数
构造函数是类中和类同名的函数,如果类中没有构造函数,编译器会自动添加无意义的构造函数
无论是创建 class对象,还是创建 struct对象,只要是定义类的对象都会自动调用类内的构造函数
1)构造函数的特点
1. 构造函数没有返回值类型
这里的没有返回值类型不是指void,而是实实在在的没有返回值类型
2. 构造函数的名字必须和当前类的类名一致
3. 类 中没有写构造函数
如果类中没有写构造函数编译器会自动补全一个内容为空的、无参无返的 构造函数
4. 构造函数允许出现多个(形参类型不完全一致)
形参类型不完全一样:参数、数量、排列组合的顺序,只要有一个不一样
当有多个版本的构造函数的时候,到底调用的是哪个版本的构造函数,取决于调用构造函数的时候,传递了什么排列组合的实参
2)构造函数的调用方式
1. 自动调用
格式:类名 对象(参数1,参数2···)
2. 手动调用
格式:类名 对象=构造函数名(参数1,参数2···)
3. 隐式调用
格式:类名 对象(单个参数)
注意:如果填写了多个参数,由于逗号运算符,只获取最后一个变量的值
格式:类名 对象={参数1,参数2···}
3)隐式调用
上述的方法中有两种被称为隐式调用,隐式调用就是我们无法直接看出调用了类的构造函数
可以通过在函数的声明前添加关键字 explicit 用于禁止隐式调用
隐式调用的示例:
隐式调用赋值,有问题
4)初始化列表
构造函数分为两个部分:内核部分和用户部分
用户部分:{}内的部分,负责执行用户自己编写的代码
内核部分:()到{}中间的部分,申请该对象所需要的所有栈空间
这部分区域,用户是可以人为干涉的
: 变量名1(初始值),变量名2(初始值),...,对象1(构造函数参数),对象2(构造函数参数),......
在列表初始化里面,()前面的一定是成员属性,()里面的就近原则
练习:
封装一个mystring类,
class mystring{
private://char buf[256];char* buf;// 指向一个堆空间,该堆空间用来保存外部传入的字符串int len; // 记录 buf里面保存的字符串有多少
public:
};要求能够实现以下功能
int main(){mystring str = "hello"; // 这段代码要求一定为mystring类写一个可隐式调用的单参构造函数mystring ptr = "world"; // 在写单参构造函数的时候,私有成员len使用列表初始化的形式初始化str.copy(ptr);str.copy("你好");str.append(ptr)str.append("你好")str.compare(ptr)str.compare("你好")str.show(); // 最后再写一个 show 函数,用来在终端输出 str 里面保存的字符串cout << str.at(0) << endl;// 再写一个 at 函数,用来输出 str中第0个字符
}
#include <iostream>
#include <cstring>
#include <iostream>
using namespace std;
class mystring
{
private:char* buf;int len;public:mystring(const char* str);void copy(const char* ptr);void copy(mystring ptr);void append(const char* ptr);void append(mystring ptr);void compare(const char* ptr);void show(){cout << buf << endl;}
};
mystring::mystring(const char* str):len(strlen(str))
{buf=(char*)malloc(len+1);strcpy(buf,str);
}//复制字符串
void mystring::copy(const char* ptr)
{int i=0;len=strlen(ptr);while(ptr[i]!='\0'){buf[i]=ptr[i];i++;}buf[i]='\0';
}void mystring::copy(mystring ptr)
{int i=0;len=ptr.len;while(ptr.buf[i]!='\0'){buf[i]=ptr.buf[i];i++;}buf[i]='\0';
}
//追加字符串
void mystring::append(const char* ptr)
{int i=0,j=0;while(buf[i]!='\0'){i++;};for(;ptr[j]!='\0';j++,i++){buf[i]=ptr[j];}buf[i]='\0'; len=i;
}void mystring::append(mystring ptr)
{int i=len,j=0;while(ptr.buf[j]!='\0'){buf[i]=ptr.buf[j];i++;j++;
}
buf[i]='\0';
len=i;}
//主函数
int main()
{mystring str = "hello";str.show();mystring ptr = "world";str.copy(ptr);str.show();str.copy("你好");str.show();str.append(ptr);str.show();str.append("你好");str.show();
}