制作人:BIN,2017.1.1
对C++的理解:
C和C++的不同之处:
C版本的hellowrold
#include<stdio.h>
void main(void)
{
printf("hell wrold\n");
}
C++版本:
#include<iostream>
using namespace std;
void main()
{
cout<<"hello wrold\n"<<endld
}
从面向过程到面向对象
面向过程编程:即结构化编程,主要思想是把大的问题化成小得问题…
面向过程编程思想的核心:功能分解,自顶向下,逐层细化(程序 = 数据结构 + 算法)。
面向过程最重要原则:高内聚,低耦合;
面向对象
算法和数据结构被看做一个整体,叫对象;
对象编程三大特性(C++)
–封装
-把客观的事物封装成抽像的类;
-类将成员变量和成员函数封装在类的内部,设置权限访问成员函数内部状态;
–继承
类和类之间的联系,使对象可以继承另外一类对象的特征和能力;
继承的作用:避免公用代码的重复开发,减少代码和数据冗余;
–多态
“一个接口,多种方法”面向对象编程领域的核心;
C++中::作用域运用:
局部变量和全局变量同名: 一个在全局变量,一个在局部变量;那么在局部变量作用域之内具有较高的优先权(就近原则)
加上::作用域的不同之处:
函数形参和类成员变量同名怎么办?
class A
{
public:
void setA(int a)
{
//当类成员变量和局部变量a同名时
//通过类名::成员变量(A::a)来引用类成员变量
A::a = a;
}
private:
int a;
};
```没多大的用,起名都是尽量少起同名的
全局变量函数和类成员同名:
![这里写图片描述](https://img-blog.csdn.net/20161229190925092?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvcXFfMzYwODg2MDI=/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast)
命名空间:
注意(二义性问题) namespace:: val 和 using namespace 的区别.
C++小细节:
C++和C中的三目运算符
![这里写图片描述](https://img-blog.csdn.net/20161229193348788?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvcXFfMzYwODg2MDI=/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast)
<div class="se-preview-section-delimiter"></div>
**const**修饰符:
--
**const** 全局变量会储存到只读数据段,都受到了只读数据段的保护,不可以修改.
![这里写图片描述](https://img-blog.csdn.net/20161229203853087?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvcXFfMzYwODg2MDI=/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast)
**const**局部变量
<div class="se-preview-section-delimiter"></div>
![这里写图片描述](https://img-blog.csdn.net/20161229205633239?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvcXFfMzYwODg2MDI=/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast)
-------------------------------------------------------------------------------
-----------------------------------------------------------------------------------------------------------------------------------------------------
![这里写图片描述](https://img-blog.csdn.net/20161229210118074?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvcXFfMzYwODg2MDI=/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast)
**define**和#**const**的区别
宏定义以后的代码代码都可以使用,有点像全局变量;
const变量有作用域访问,只能在作用域起作用,
**引用**
在C++中可以用引用给变量起一个别名;**引用可以看作一个已定义变量的别名(使用效果和指针一样)。** **(引用定义的时候必须初始化)**
**引用**做函数参数
引用参数产生的效果同按地址传递是一样的。引用的语法更清楚简单;如下图:
![这里写图片描述](https://img-blog.csdn.net/20161229212914047?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvcXFfMzYwODg2MDI=/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast)
修改变量值的三种方法:`//1、直接修改
a = 1;
cout << a << endl;
//2,通过指针间接赋值
int *p = NULL;
p = &a;
*p = 2;
cout << a << endl;
//,引用
int &b = a; //给a起别名b
b = 3;
cout << b << endl;`
函数返回值是引用:
![这里写图片描述](https://img-blog.csdn.net/20161229215649505?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvcXFfMzYwODg2MDI=/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast)
<div class="se-preview-section-delimiter"></div>
**常引用(用const修饰)**:
--
常引用主要用于函数参数,只能读,不能写
<div class="se-preview-section-delimiter"></div>
![这里写图片描述](https://img-blog.csdn.net/20161230131850071?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvcXFfMzYwODg2MDI=/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast)
-----------------------------------------------------------
----------------------------------------------------
**内联函数**
空间换时间
内联函数只是一种请求,编译器不一定允许这种请求
圣墟
**默认(缺省)参数的函数**:
1,函数设置默认参数,必须从右往左设置,而且是连续的
<div class="se-preview-section-delimiter"></div>
//void fun1(int a = 1, int b) //err
//void fun2(int a = 1, int b, int c = 10) //err
void fun3(int a, int b = 10, int c = 20)
{
}
如果函数声明和定义分开,默认参数只在声明时定义,定义的地方不能设置默认参数
<div class="se-preview-section-delimiter"></div>
//void fun4(int a = 10, int b = 20) //err
void fun4(int a, int b)
{
}
占位符参数:
<div class="se-preview-section-delimiter"></div>
include
using namespace std;
//占位参数, 最后一个参数为占位参数
void test(int a, int b, int)
{
cout << “test ====== ” << a << “,” << b << endl;
}
//默认参数和占位参数结合使用
void test2(int a = 10, int b = 20, int = 30)
{
}
int main()
{
//test(2, 3); //err
test(2, 3, 1); //占位参数也是参数,需要把实参写全才能调用
test2();
test2(1);
test2(1, 2);
test2(1, 2, 3);
return 0;
}
<div class="se-preview-section-delimiter"></div>
**函数重载**
--
C++中允许出现同名的函数,这种现象称为函数重载
**重载的条件**
1)同一个作用域;
2)参数个数不同;
3)参数类型不同;
4)参数顺序不同;
**extern"C"浅析**
extern "C"的主要作用就是为了实现C++代码能够调用其他C语言代码.
`其他话题
我在一次项目中遇到头文件重复包含,但有变量必须要用到这个头文件,所以使用了**extern**,很无语那个时候搞了半天;`
函数声明放在extern "C"内部:
<div class="se-preview-section-delimiter"></div>
//防止头文件重复包含
pragma once
//extern “C” 让C代码可以在C++编译器编译, 兼容C++编译器
//__cplusplus是编译器提供好的宏,不是自定义的
ifdef __cplusplus
extern “C”{ //告诉编译器按C语言的方式进行编译和链接,而不是按C++的方式
endif // __cplusplus
//函数的声明
ifdef __cplusplus
}
endif // __cplusplus
头文件包含放在extern "C"内部
<div class="se-preview-section-delimiter"></div>
extern “C”
{
#include “xxx.h” //xxx.h文件中函数用C标准编译代码
}
函数声明前面加extern "C"
<div class="se-preview-section-delimiter"></div>
extern “C” void func(int a);
类和对象:
封装和访问权限:
--封装:
把变量(属性)和函数(操作)合成一个整体,封装在一个类中
访问权限:
1)在类的内部(作用域范围内),没有访问权限之分,所有成员可以相互访问
2)2)在类的外部(作用域范围外),**访问权限才有意义**:public,private,protected
![这里写图片描述](https://img-blog.csdn.net/20161230203218012?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvcXFfMzYwODg2MDI=/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast)
struct和class的区别:
struct不写访问权限,默认是public;
class不写访问权限,默认是private;
类和对象的关系:
类,相当于设计图,对象,根据设计图创造出来的实物,即,类是对象的抽象,对象是类的实例;
构造函数分类:
<div class="se-preview-section-delimiter"></div>
class A
{
public:
A()//无参
{
cout << “无参构造函数\n”;
}
//有参
//普通构造函数
A(int a)
{
cout << "有参构造函数:a = " << a << endl;
}
A(int a, int b)
{
cout << "有参构造函数2:a = " << a << ", b =" << b << endl;
}
//拷贝构造函数,形参为本类一个对象的别名
//功能:旧对象初始化新对象
A(const A &tmp)//参数为:const修饰本类对象的引用
{
cout << "拷贝构造函数\n";
}
};
构造函数调用时机:
<div class="se-preview-section-delimiter"></div>
include
using namespace std;
class A
{
public:
A()
{
cout << “无参构造函数\n”;
}
//有参
//普通构造函数
A(int a)
{
cout << "有参构造函数:a = " << a << endl;
}
A(int a, int b)
{
cout << "有参构造函数2:a = " << a << ", b =" << b << endl;
}
//拷贝构造函数,形参本类一个对象的别名
//功能:旧对象初始化新对象
A(const A &tmp)
{
cout << "拷贝构造函数\n";
}
};
//无参构造函数调用方法的正确写法
void fun()
{
A obj; //调用无参
//无参构造函数错误调用方法
//A obj2(); //err,此种形式为函数声明,函数返回值是一个对象
}
//有参构造函数调用方法
void fun2()
{
//1、括号法,最常用
A obj(10);
A obj2(1, 2);
//拷贝构造函数,旧对象obj初始化新对象tmp
A tmp(obj);
//2、显性调用构造函数,匿名对象,没名字的对象
A(11); //匿名对象,没名字的对象,常用于给函数传参
A obj3 = A(22);
A obj4 = A(33, 44);
//3、= 号法,面试时常问,不常用,了解
A obj5 = 11; //隐式转换,将整形11转换为A(11)
A obj6 = (4, 5, 6); //逗号运算符,最后一个数字有效
}
int main()
{
fun();
fun2();
return 0;
}
匿名对象的生命周期,如果不用,编译器立马释放
<div class="se-preview-section-delimiter"></div>
**浅拷贝**
--
浅拷贝就是增加一个指针指向一个已经存在的内存;
一般情况下,浅拷贝没有任何副作用,当类中有指针,并且此有指针动态分配空间,析构函数释放处理,会导致内存问题
浅拷贝错误示例:
<div class="se-preview-section-delimiter"></div>
include
using namespace std;
class A
{
public:
A(const char *tmpName = “abc”)
{
//+1,为了放字符串结束符‘\0’
name = (char *)malloc(strlen(tmpName) + 1);
if (name != NULL)
{
strcpy(name, tmpName);
}
}
~A()
{
free(name);
}
char *getName()
{
return name;
}
private:
char *name;
};
void fun()
{
A obj(“bin”); //A(char *tmpName = “abc”)
cout << obj.getName() << endl;
//拷贝构造函数
//由于用户没有定义,则调用默认的拷贝构造函数,浅拷贝
A tmp = obj;
cout << tmp.getName() << endl;
}
int main()
{
fun();
return 0;
}
浅拷贝示例图:
![这里写图片描述](https://img-blog.csdn.net/20170102174101314?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvcXFfMzYwODg2MDI=/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast)
上示例图中两个指针指变量向了同一块内存,当两个对象析构时,同一块内存区域会释放两次,导致内存问题,但是一个类中不写析构函数,会导致内存泄漏;
<div class="se-preview-section-delimiter"></div>
**深拷贝**
--
深拷贝就是增加一个指针并且申请一个新的内存,使这个增加的指针指向这个新的内存
当类中有指针,并且此有指针动态分配空间,就需要**深拷贝**;
需加上自定义拷贝函数,在分配内存空间;
<div class="se-preview-section-delimiter"></div>
//自定义拷贝构造函数,深拷贝
A(const A &tmp)
{
name = (char *)malloc(strlen(tmp.name) + 1);
if (name != NULL)
{
strcpy(name, tmp.name);
}
}
![这里写图片描述](https://img-blog.csdn.net/20170102180033679?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvcXFfMzYwODg2MDI=/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast)
参数列表 (初始化列表)
有些小伙伴不知道这个是什么意思?
<div class="se-preview-section-delimiter"></div>
// A(int x, int y, int z) //传统方式初始化
// {
// a = x;
// b = y;
// c = z;
// }
<div class="se-preview-section-delimiter"></div>
//参数列表方式给成员变量初始化
A(int x, int y, int z) : a(x), b(y), c(z){}
对于const常量初始化
<div class="se-preview-section-delimiter"></div>
A(int x, int y, int z) : a(x), b(y), c(z), d(5){}
<div class="se-preview-section-delimiter"></div>
**explicit关键字**
--
C++中的explicit关键字抑制由构造函数定义的隐式转换。explicit关键字只能用于类内部的构造函数声明上,而且是针对单参数的构造函数
**对象的动态创建(new)和释放(delete)**
在C语言中我们用的的malloc和free来创建和释放内存空间
在C++中 建议使用new和delete;
重点用在类对像的申请与释放。申请的时候会调用构造器完成初始化,释放的时候,会调用析构器完成内存的清理;
一般格式为:
![这里写图片描述](https://img-blog.csdn.net/20170102192227749?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvcXFfMzYwODg2MDI=/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast)
**注意:**
用了new就要用delete;不要和malloc,free混合使用;
使用new[]创建了数组,必须要在delete中释放数组
<div class="se-preview-section-delimiter"></div>
int *p2 = NULL;
p2 = new int[10];
delete[] p2;
<div class="se-preview-section-delimiter"></div>
**static**
--
在类定义中,关键字static声明为静态的,称为静态成员
**静态成员变量必须在类中声明,在类外定义**
静态成员变量,属于某个类,所有对象共享
没有创建对象前就可以访问static变量;
<div class="se-preview-section-delimiter"></div>
cout << A::s << endl;
操作成员static两种方法:
<div class="se-preview-section-delimiter"></div>
//1、类名::变量
A::s = 100;
A t1, t2, t3;
//2、对象.变量
t2.s = 21;
一个类的成员,既要实现共享,又要实现不可改变,那就用 static const 修饰
<div class="se-preview-section-delimiter"></div>
include
using namespace std;
class A
{
public:
static void fun()
{
//i = 10; //err
cout << i << endl;
}
private:
//最好在类内部初始化
static const int i = 100;
//const static int i = 100;
};
int main()
{
A::fun();
return 0;
}
**在计算类的大小的时候不考虑static共享成员**
<div class="se-preview-section-delimiter"></div>
class A
{
private:
static int d; //4
int a; //4
};//8 还是 4
int main()
{
A obj;
//结果为4
cout << “sizeof(obj) = ” << sizeof(obj) << endl;
}
友元类......关键字**friend**
友元函数不是类中的成员函数,是一个普通全局函数
函数在外部定义时不需要加作用域
**this指针**
关于this指针的一个经典回答:
当你进入一个房子后,
你可以看见桌子、椅子、地板等,
但是房子你是看不到全貌了。
对于一个类的实例来说,
你可以看到它的成员函数、成员变量,
但是实例本身呢?
this是一个指针,它时时刻刻指向你这个实例本身;
this的使用:a)当形参和成员变量同名时,可通过this指针来区分,如this->n = n (不能写成n = n)
b) 返回调用该成员函数对象的引用;
对于这一点我有点迷茫
直接上代码:
<div class="se-preview-section-delimiter"></div>
include
using namespace std;
class A
{
public:
A& setA(int a)
{
this->a = a;
return *this;
}
void show()
{
cout << "a = " << a << endl;//a=20
}
private:
int a;
};
int main()
{
A obj;
obj.setA(20).show();
return 0;
} //this->a
//return *this 说白了就是return成员变量的值;this指向的内存空间里的值;
**const修饰的成员函数和对象(常对象)**
const修饰成员函数时,onst修饰this指针指向的内存区域,成员函数体内不可以修改本类中的任何普通成员变量.除非 成员变量类型符前加关键字**mutable**
常对象只能调用const的成员函数
常对象可访问 const 或非 const 数据成员,不能修改,除非成员用**mutable**修饰
指向类成员的指针
在C++语言中,可以定义一个指针,使其指向类成员或成员函数,然后通过指针来访问类的成员。这包括指向成员变量的指针和指向成员函数的指针。
2.6.1 指向类成员变量的指针
定义格式
<数据类型><类名>::*<指针名>
赋值&初始化
<数据类型><类名>::*<指针名>[=&<类名>::<非静态数据成员>]
解用引
<类对象名>.*<指向非静态数据成员的指针>
<类对象指针>->*<指向非静态数据成员的指针>
使用实例:
<div class="se-preview-section-delimiter"></div>
include
include
using namespace std;
class Student
{
public:
Student(string n, int nu) :name(n), num(nu){}
string name;
int num;
};
int main()
{
Student s(“lily”, 1002);
Student s2(“lilei”, 1001);
string *p1 = &s.name; //普通指针变量
cout<< *p1<<endl;
//1、p2为指向类中name成员的指针变量
//2、*p2就相当于name成员
string Student::*p2 = &Student::name;
cout << s.*p2 << endl;
cout << s2.*p2 << endl;
int Student::*p3 = &Student::num;
cout << s.*p3 << endl;
cout << s2.*p3 << endl;
Student *p4 = new Student("xiaoming", 1003);
cout << p4->*p2 << endl;
return 0;
}
指向类成员函数的指针
定义一个指向非静态成员函数的指针必须在三个方面与其指向的成员函数保持一致:参数、返回类型、所属的类型。
定义格式
<数据类型>(<类名>::*<指针名>)(<参数列表>)
赋值&初始化
<数据类型>(<类名>::*<指针名>)(<参数列表>)[=&<类名>::<非静态成员函数>]
解用引
(<类对象名>.*<指向非静态成员函数的指针>)(<参数列表>)
(<类对象指针>->*<指向非静态成员函数的指针>)(<参数列表>)
使用实例:
<div class="se-preview-section-delimiter"></div>
include
include
using namespace std;
class Student
{
public:
Student(string n, int nu) :name(n), num(nu){}
void dis()
{
cout << “name ” << name << ” num ” << num << endl;
}
private:
string name;
int num;
};
int main()
{
Student s(“lily”, 1);
Student s2(“mike”, 2);
Student *p1 = new Student(“xiaoming”, 3);
void (Student::*pf)() = &Student::dis; //必须要&符号
(s.*pf)();
(s2.*pf)();
(p1->*pf)();
return 0;
}
指向类静态成员的指针
指向类静态数据成员的指针
指向静态数据成员的指针的定义和使用与普通指针相同,在定义时无须和类相关联,在使用时也无须和具体的对象相关联。
指向类静态成员函数的指针
指向静态成员函数的指针和普通指针相同,在定义时无须和类相关联,在使用时也无须和具体的对象相关联。
使用示例:
<div class="se-preview-section-delimiter"></div>
include
include
using namespace std;
class A
{
public:
static void dis();
static int data;
};
void A::dis()
{
cout << data << endl;
}
int A::data = 100;
int main()
{
int *p = &A::data;
cout << *p << endl;
void(*pfunc)() = A::dis;
pfunc();
return 0;
}
<div class="se-preview-section-delimiter"></div>
**运算符重载**
--
所谓重载,就是重新赋予新的含义,相当于"一词多用",在C++中,运算符也可以重载;运算符重载也叫运算符重载函数,它就是函数的重载
具体可以参照https://wuyuans.com/2012/09/cpp-operator-overload/
可重载和不可重载运算符:
![这里写图片描述](https://img-blog.csdn.net/20170103205945965?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvcXFfMzYwODg2MDI=/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast)
特殊运算符
=, [], () 和 -> 操作符只能通过成员函数进行重载
<< 和 >> 操作符最好通过友元函数进行重载
不要重载 && 和 || 操作符,因为无法实现短路规则
具体看一些实例:
自加运算符重载++
<div class="se-preview-section-delimiter"></div>
include
using namespace std;
class Complex
{
friend Complex &operator++(Complex &c); //前置++
friend Complex operator++(Complex &c, int);//后置++, 多了一个占位符
public:
Complex(int x = 0, int y = 0) :a(x), b(y) {}
void display() const
{
cout << a << " + " << b << "i" << endl;
}
private:
int a, b;
};
//前置++,先加后用
Complex &operator++(Complex &c)
{
c.a++;
c.b++;
return c;
}
//后置++, 先用后加
Complex operator++(Complex &c, int)
{
Complex tmp = c;
c.a++;
c.b++;
return tmp;
}
int main()
{
Complex c(1, 2);
//前置++, 先加后用
Complex tmp = ++c; //函数原型: operator++(Complex &c);
tmp.display();
c.display();
//后置++, 先用后加,多了一个占位符参数int,表示后置操作
Complex tmp2 = c++; //函数原型: operator++(Complex &c, int);
tmp2.display();
c.display();
return 0;
}
2)赋值运算符重载 =
<div class="se-preview-section-delimiter"></div>
include
using namespace std;
class Test
{
public:
Test(char *buf = “abc”) //普通构造函数
{
str = new char[strlen(buf) + 1];
strcpy(str, buf);
}
//拷贝构造函数
Test(const Test &obj)
{
str = new char[strlen(obj.str) + 1];
strcpy(str, obj.str);
}
void display()
{
cout << "str = " << str << endl;
}
//析构函数
~Test()
{
if (NULL != str)
{
delete[] str;
str = NULL;
}
}
//等号运算符重载,只能作为成员函数
//如果函数做左值,必须返回引用
Test &operator=(const Test &t)
{
if (this->str != NULL)
{
//str , this->str等价
delete[]str;
str = NULL;
}
str = new char[strlen(t.str) + 1];
strcpy(str, t.str);
return *this;
}
private:
char *str;
};
int main()
{
Test obj1(“bin”); //调用普通构造函数
//调用拷贝构造函数
//旧对象初始化新对象
//Test obj2(obj1);
Test obj2 = obj1;
obj2.display();
Test obj3("bin1");
obj2 = obj3 = obj1; //旧对象重新给旧对象赋值
//函数调用:obj2.operator=(obj3);
//函数原型:Test &operator=(Test &t);
obj2.display();
return 0;
}
<div class="se-preview-section-delimiter"></div>
**下标重载**
--
<div class="se-preview-section-delimiter"></div>
include
using namespace std;
class MyArray
{
public:
MyArray(int tmpLen = 1) //普通构造函数
{
space = new int[tmpLen];
len = tmpLen;
}
~MyArray()//析构函数
{
if (space != NULL)
{
delete[]space;
space = NULL;
len = 0;
}
}
//获取元素个数,长度
int getLen() const
{
return len;
}
//[]重载,必须作为成员函数
int & operator[](int index)
{
return space[index];
}
private:
int len; //数组元素个数
int *space; //空间
};
int main()
{
MyArray obj(10);
//设置数组的值
for (int i = 0; i < obj.getLen(); i++)
{
obj[i] = i + 1; //函数做左值,必须返回引用
}
//获取数组的值
for (int i = 0; i < obj.getLen(); i++)
{
cout << obj[i] << " ";
}
cout << endl;
return 0;
}
<div class="se-preview-section-delimiter"></div>
**等号不等号重载== =!**
--
<div class="se-preview-section-delimiter"></div>
include
using namespace std;
class MyArray
{
public:
MyArray(int tmpLen = 1) //普通构造函数
{
space = new int[tmpLen];
len = tmpLen;
}
~MyArray()//析构函数
{
if (space != NULL)
{
delete[]space;
space = NULL;
len = 0;
}
}
//获取元素个数,长度
int getLen() const
{
return len;
}
//[]重载,必须作为成员函数
int & operator[](int index)
{
return space[index];
}
//==重载
bool operator==(MyArray &obj)
{
if (this->len != obj.len)
{
return false;
}
MyArray &tmp = *this;
for (int i = 0; i < this->len; i++)
{
if (tmp[i] != obj[i])
{
return false;
}
}
return true;
}
//!= 重载
bool operator!=(MyArray &obj)
{
MyArray &tmp = *this;
return !(tmp == obj);
}
private:
int len; //数组元素个数
int *space; //空间
};
int main()
{
MyArray obj1(10);
for (int i = 0; i < obj1.getLen(); i++)
{
obj1[i] = i + 1; //函数做左值,必须返回引用
}
MyArray obj2(10);
for (int i = 0; i < obj2.getLen(); i++)
{
obj2[i] = i + 1; //函数做左值,必须返回引用
}
if (obj1 == obj2)
{ //函数调用:obj1.operator==(obj2);
//函数原型:bool operator==(MyArray &obj);
cout << "相等\n";
}
else if (obj1 != obj2)
{//函数调用:obj1.operator!=(obj2);
//函数原型:bool operator!=(MyArray &obj);
cout << "不相等\n";
}
return 0;
}
<div class="se-preview-section-delimiter"></div>
**函数调用重载符**
-
<div class="se-preview-section-delimiter"></div>
include
using namespace std;
class MyArray
{
public:
MyArray(int tmpLen = 1) //普通构造函数
{
space = new int[tmpLen];
len = tmpLen;
}
~MyArray()//析构函数
{
if (space != NULL)
{
delete[]space;
space = NULL;
len = 0;
}
}
//获取元素个数,长度
int getLen() const
{
return len;
}
//[]重载,必须作为成员函数
int & operator[](int index)
{
return space[index];
}
//==重载
bool operator==(MyArray &obj)
{
if (this->len != obj.len)
{
return false;
}
MyArray &tmp = *this;
for (int i = 0; i < this->len; i++)
{
if (tmp[i] != obj[i])
{
return false;
}
}
return true;
}
//!= 重载
bool operator!=(MyArray &obj)
{
MyArray &tmp = *this;
return !(tmp == obj);
}
private:
int len; //数组元素个数
int *space; //空间
};
int main()
{
MyArray obj1(10);
for (int i = 0; i < obj1.getLen(); i++)
{
obj1[i] = i + 1; //函数做左值,必须返回引用
}
MyArray obj2(10);
for (int i = 0; i < obj2.getLen(); i++)
{
obj2[i] = i + 1; //函数做左值,必须返回引用
}
if (obj1 == obj2)
{ //函数调用:obj1.operator==(obj2);
//函数原型:bool operator==(MyArray &obj);
cout << "相等\n";
}
else if (obj1 != obj2)
{//函数调用:obj1.operator!=(obj2);
//函数原型:bool operator!=(MyArray &obj);
cout << "不相等\n";
}
return 0;
}
<div class="se-preview-section-delimiter"></div>
**继承**
-
解决了代码的重复的问题;
派生类定义格式:
<div class="se-preview-section-delimiter"></div>
class 派生类类名::继承方式 基类名
{
//…….//
};
“`
继承共有三个继承方式:public(公有),private(私有),protected(保护)
单继承:指每个派生类只直接继承了一个基类的特征;
多继承:指多个基类派生出一个派生类的继承关系,多继承的派生类直接继承了不止一个基类的特征;
派生类的访问权限:
改造
class 派生类类名::继承方式 基类名
{
//.......//
};
继承共有三个继承方式:public(公有),private(私有),protected(保护)
单继承:指每个派生类只直接继承了一个基类的特征;
多继承:指多个基类派生出一个派生类的继承关系,多继承的派生类直接继承了不止一个基类的特征;
派生类的访问权限: