1.采用原因:由于刚从c语言面向过程的学习中解脱出来,立即把思路从面向过程转到面向对象肯定不现实,加之全新的复杂语法与操作,着实给新手学习这门语言带来了不小的困难。所以,笔者探索出了一种好用的学习方法:模板法。
2.采用方法:在接触新知识时,没有必要从一开始便理清新知识的来龙去脉,可以先去csdn上学习新知识的模板和语法,再写一些简单程序以强化理解。在听完学校的课程后,写作业时,可以先使用ai写一道简单题并学习其格式和逻辑,再自己写难题
1.采用范围:程序报错且错误在认知范围内,如果遇到认知范围外的错误或者不报错却运行不了,请直接找老师解决或者用AI检验
2.为什么笔者觉得它比调试更加高效?因为在调试的时候,为了理清监视变量的变化,需要在循环的每一步认真分析,这样会浪费大量时间。所以,笔者在程序报错时,首先会检查指针越界和数组循环问题,然后分块将代码注释并运行,通过成功运行的部分不断扩大最终找到问题所在,或者当itc报错而不显示输入数据时,在每次输入后都打印一遍以获得数据,在检查类的析构,构造,组合,多态等复杂的问题时,让每个函数都打印特定的值,以确定函数失效的部分
1.数据的封装:在一个类中,有public,private,protected三种成员,它们对应了不同的保密程度,这点与数据封装有关,它们的区别是public可以由任意操作进行访问,而protected只能由本类和子类的成员函数访问(子类笔者下文会讲),private的封装性更好,只能由本类的成员函数访问(注意:在自己写题的时候尽量写成public类,一是写题没有封装性要求,二是防止因自己写的子类函数无法访问基类成员而纠错),三种成员必须显示声明如public:再写public类型的数据成员与成员函数,否则默认为private类型。
2.成员:在一个类中,有几个固定的组成部分:数据成员与成员函数。其中成员是类所具有的数据,如整型,浮点型,字符型,数组指针甚至其他的类。具体参考c语言的结构体,而成员函数有以下三种:构造函数(必须显示声明,分为三种:默认构造函数,赋值构造函数与复制构造函数,默认构造函数的格式为类型名(){}; ,赋值构造函数就和普通的函数一样,将实参复制为形参,复制后释放,复制构造函数既可以显示声明也可以不声明,系统自己会生成一个,但如果要用记得声明,它的格式如下):
class good
{
public:
int b;
good(){};
good(const good &a)
{
b=a.b;
}
};
普通成员函数:和写在类外的函数只有一个区别,就是它可以调用本类中的一切数据成员
析构函数,与构造函数的格式类似,前面需要加一个~(小提示:键盘左上角),它可以自己定义,或者由系统自动生成,往往与打印某些语句有关。
3.new与delete,这两个函数的使用参考malloc与free,笔者在动态内存存储中有讲,动态内存管理-CSDN博客,只要使用了new,就必须显示声明析构函数并将空间delete掉(delete[]表示释放一个数组的空间),至于原因,就由下面的话题来解释◕‿◕
1.不出意外,我们的所有数据都进行了深拷贝,即成功拷贝,可以理解为不报错的拷贝。
2.但是不出意外的情况下还是出意外了,当我们准备拷贝指针以及指针类型的数据(字符串,数组,函数,类)时出现了一个问题,这些拷贝的都是目标内存空间的地址,地址只有一个,所以,当复制构造完成时,我们的对象a(书接上文代码)就被释放了,而这些空间被释放后,原对象也会对这些空间进行释放,但它们已经不存在了,所以就出现了错误。
3.解决方法:给这些数据一个新的空间,把指针指向的数据放进去,这时候指针只是一个媒介,只是指指路,真正操作的是它指向空间的数据
4.代码演示
class good
{
public:
int *p;//此处一般为数组
good (const good& d)//拷贝构造函数,深拷贝版
{
p = new char[strlen(d.p) + 1];//为这个指针申请一个新空间
if (p != 0)
{
strcpy(p, d.p);//只操作数据,不操作指针,析构记得delete
};
1.为什么要有多态性:俗话说:“一千个读者就有一千个哈姆雷特”,在生活中,我们使用同一个工具,在不同场景中的使用方法和结果是不一样的,而c++中的函数重载正是还原了这点。一个函数,因为参数,函数体,返回结果的不同,实现了多种实现方式,这就是传说中的多态性。
2.函数重载的方法:一个函数名,因不同参数而产生不同情况。所以可以在这些情况下随意使用,不需要写多个函数,增加了代码的可读性,代码如下:
int add(int a,int b)
{
return a+b;
}
float add(float a,float b)
{
return a+b;
}
1.为什么要引入类的组合与类的继承?因为c++在尽力复刻生活中的关系,比如机器与零件的组合关系以及父与子之间的继承关系。
2.格式:类的组合在大类中的声明和数据成员一样,如good a;,但注意组合类的声明必须在大类之前,类的继承必须保证基类函数在子类函数之前声明,继承有三种方式,public,protected和private,不同的方式下继承导致成员类型发生变化的情况如下表:
3.继承格式:class 子类名:继承方式 基类名
4.继承方式分为单继承与多继承,即父类与子类对象一对一和多对一,已知子类可以调用父类的成员和成员函数,那么出现重叠怎么办?所以,就有了如下定义:
1.虚基类引入目的:解决代码在多继承中出现的冲突问题,由最远的基类成员来提供基类数据,注意引入时要在第一级继承时将共同基类设置为虚基类(在继承类型前加virtual )
2.顺序问题请看下表
注意析构函数的执行过程与构造函数相反,先构造后析构。
3.虚成员函数(必须为非静态函数):它的功能是在基类中定义的虚函数,子类可根据自身情况进行覆写以达到不同的需求。格式就是在函数前面加上virtual
4.虚析构函数(用的少):作用就是通过基类指针删除对象或者调用对象的析构函数,格式就是在~前加个virtual
5.纯虚函数与抽象类:当一个函数虚到只有一个函数名是重要的时候,会以virtual 函数名 形参表=0的形式输出,而含有纯虚函数的类叫做抽象类,它具有以下特点:
6.每个子类都要把基类的全部纯虚函数都重写一遍,哪怕是空函数,注意是全部!
1.通过运算符重载,我们就可以实现有关类的一切运算
2.运算符重载有两种方式,一种是类的成员函数,一种是类的友元函数(在函数或者类前面加个friend代表此函数或者此类可以访问该类的成员及成员函数),前者的格式为:返回类型 operator& 需要重载的运算符(除了本类外的其他参数或类){实现过程}(注意*this代表本函数的指针),后者的格式就是在前者格式的最前面加一个friend在参数多加一个类)
3.本快知识就是模板,笔者做过一道题,读者可以参考一下,模板和方法比较全:
【问题描述】实现Mystring类,类结构如下
class MyString{
private:
char str[1024];
unsigned len;/*字符串长度*/
public:
MyString()
MyString& operator=(const char *mstr)/*常量字符串赋值*/
MyString& operator=(const MyString mstr)/*同类型赋值*/
MyString operator+(const MyString mstr)/*字符串拼接*/
char &operator [](int i)/*查询串内字符*/
bool operator==(const MyString mstr)/*判断是否相等*/
bool operator!=(const MyString mstr)/*判断是否不等*/
void operator+=(const MyString mstr)/*字符串拼接赋值*/
bool operator>(const MyString mstr)/*按典序比较*/
bool operator<(const MyString mstr)}/*同上*/
friend ostream &operator<<(ostream &out,const MyString mstr);/*友元输出流符号重载*/
};
主函数结构如下:
int main()
{
char ts[1024];
cin>>ts;
MyString s;
s = ts;
cin>>ts;
MyString ss;
ss = ts;
if(ss == s)
cout<<"equal"< if(ss != s) { cout<<"Not equal"< if(s > ss) cout<<"s da yu ss"< if(s < ss) cout<<"s xiao yu ss"< } ss += s; MyString sss; sss = s + ss; sss[0] = '$'; cout< return 0; } #请勿修改主函数,请勿使用C++的string类# 【输入形式】两个字符串,以换行隔开; 【输出形式】调用所给main函数 【样例输入】 abcd abcde 【样例输出】 Not equal s xiao yu ss $bcdabcdeabcd 运算符重载 · 王赫辰/c语言 - Gitee.com