目录
一、运算符重载
1.1普通运算符重载
1.2特殊运算符重载
二、标准输入输出流
三、组合与继承
3.1组合
3.2继承
1) public继承方式
2) protected继承方式
3) private继承方式
小作业:模仿c++的string类,自己实现string类
一、运算符重载
百度百科-验证
1.1普通运算符重载
//C++准许以运算符命名函数!!!
string a = “hello”;
a += “ world”;// +(a, “world”);
cout<<“hello”; // <<(cout, “hello”);
可重载的运算符
不可重载的运算符
下面用一个例子来展示重载的妙处:
#include <stdio.h>
#include <unistd.h>
class Timer{
public:
Timer()
{
hour = 0;
min = 0;
sec = 0;
}
~Timer()
{
}
void addtimer(int sec = 1)
{
this->min += (this->sec+sec)/60;
this->sec = (this->sec + sec) % 60;
}
void show()
{
printf("%2d:%2d:%2d\n", hour, min, sec);
}
private:
int hour;
int min;
int sec;
};
int main()
{
Timer t;
while(1)
{
t.addtimer(1);
t.show();
sleep(1);
}
}
如果我想向下面这样
#include <stdio.h>
#include <unistd.h>
class Timer{
public:
Timer()
{
hour = 0;
min = 0;
sec = 0;
}
~Timer()
{
}
void addtimer(int sec = 1)
{
this->min += (this->sec+sec)/60;
this->sec = (this->sec + sec) % 60;
}
void show()
{
printf("%2d:%2d:%2d\n", hour, min, sec);
}
private:
int hour;
int min;
int sec;
};
int main()
{
Timer t;
t.addtimer(3);
Timer t1;
t1.addtimer(5);
Timer t2;
t2 = t + t1;
t2.show();
#if 0
while(1)
{
t.addtimer(1);
t.show();
sleep(1);
}
#endif
}
结果就是报错,但是他提醒我们可以重载
#include <stdio.h>
#include <unistd.h>
class Timer{
public:
Timer()
{
hour = 0;
min = 0;
sec = 0;
}
~Timer()
{
}
void addtimer(int sec = 1)
{
this->min += (this->sec+sec)/60;
this->sec = (this->sec + sec) % 60;
}
void show()
{
printf("%2d:%2d:%2d\n", hour, min, sec);
}
Timer operator+(Timer &x)
{
Timer tem;
tem.sec = sec + x.sec;
tem.min = min + x.min;
tem.hour = hour + x.hour;
return tem;
}
private:
int hour;
int min;
int sec;
};
int main()
{
Timer t;
t.addtimer(3);
Timer t1;
t1.addtimer(5);
Timer t2;
t2 = t + t1;
t2.show();
#if 0
while(1)
{
t.addtimer(1);
t.show();
sleep(1);
}
#endif
}
#include <stdio.h>
#include <unistd.h>
class Timer{
public:
Timer()
{
hour = 0;
min = 0;
sec = 0;
}
~Timer()
{
}
void addtimer(int sec = 1)
{
this->min += (this->sec+sec)/60;
this->sec = (this->sec + sec) % 60;
}
void show()
{
printf("%2d:%2d:%2d\n", hour, min, sec);
}
Timer operator+(Timer &x)
{
Timer tem;
tem.sec = sec + x.sec;
tem.min = min + x.min;
tem.hour = hour + x.hour;
return tem;
}
private:
int hour;
int min;
int sec;
};
int main()
{
Timer t;
t.addtimer(3);
Timer t1;
t1.addtimer(5);
Timer t2;
t2 = t + t1;
t2.show();
t2 = t2 + 5;
t2.show();
#if 0
while(1)
{
t.addtimer(1);
t.show();
sleep(1);
}
#endif
}
这次又不行了,那就再重载一次。
#include <stdio.h>
#include <unistd.h>
class Timer{
public:
Timer()
{
hour = 0;
min = 0;
sec = 0;
}
~Timer()
{
}
void addtimer(int sec = 1)
{
this->min += (this->sec+sec)/60;
this->sec = (this->sec + sec) % 60;
}
void show()
{
printf("%2d:%2d:%2d\n", hour, min, sec);
}
Timer operator+(int sec)
{
Timer tem;
tem.sec = this->sec + sec;
return tem;
}
Timer operator+(Timer &x)
{
Timer tem;
tem.sec = sec + x.sec;
tem.min = min + x.min;
tem.hour = hour + x.hour;
return tem;
}
private:
int hour;
int min;
int sec;
};
int main()
{
Timer t;
t.addtimer(3);
Timer t1;
t1.addtimer(5);
Timer t2;
t2 = t + t1;
t2.show();
t2 = t2 + 5;
t2.show();
#if 0
while(1)
{
t.addtimer(1);
t.show();
sleep(1);
}
#endif
}
剩下的就都一样了,加减乘除对应换就行了
前++和后++不一样
#include <stdio.h>
#include <unistd.h>
class Timer{
public:
Timer()
{
hour = 0;
min = 0;
sec = 0;
}
~Timer()
{
}
void addtimer(int sec = 1)
{
this->min += (this->sec+sec)/60;
this->sec = (this->sec + sec) % 60;
}
void show()
{
printf("%2d:%2d:%2d\n", hour, min, sec);
}
Timer operator+(int sec)
{
Timer tem;
tem.sec = this->sec + sec;
return tem;
}
Timer operator+(Timer &x)
{
Timer tem;
tem.sec = sec + x.sec;
tem.min = min + x.min;
tem.hour = hour + x.hour;
return tem;
}
Timer operator++(int)
{
Timer tem = *this;
sec++;
return tem;
}
Timer operator++()
{
sec++;
return *this;
}
private:
int hour;
int min;
int sec;
};
int main()
{
Timer t;
t.addtimer(3);
Timer t1;
t1.addtimer(5);
Timer t2;
t2 = t + t1;
t2.show();
t2 = t2 + 5;
t2.show();
Timer t3 = t2++;
t3.show();
++t3;
t3.show();
#if 0
while(1)
{
t.addtimer(1);
t.show();
sleep(1);
}
#endif
}
C++要求我们最好使用前++
因为后++需要先存一次,如果内容太大会很慢。
#include <stdio.h>
#include <unistd.h>
class Timer{
public:
Timer()
{
hour = 0;
min = 0;
sec = 0;
}
~Timer()
{
}
void addtimer(int sec = 1)
{
this->min += (this->sec+sec)/60;
this->sec = (this->sec + sec) % 60;
}
void show()
{
printf("%2d:%2d:%2d\n", hour, min, sec);
}
Timer operator+(int sec)
{
Timer tem;
tem.sec = this->sec + sec;
return tem;
}
Timer operator+(Timer &x)
{
Timer tem;
tem.sec = sec + x.sec;
tem.min = min + x.min;
tem.hour = hour + x.hour;
return tem;
}
Timer operator++(int)
{
Timer tem = *this;
sec++;
return tem;
}
Timer operator++()
{
sec++;
return *this;
}
bool operator==(Timer &x)
{
if(sec == x.sec && min == x.min && hour == x.hour)
return true;
return false;
}
private:
int hour;
int min;
int sec;
};
int main()
{
Timer t;
t.addtimer(3);
Timer t1;
t1.addtimer(5);
Timer t2;
t2 = t + t1;
t2.show();
t2 = t2 + 5;
t2.show();
Timer t3 = t2++;
t3.show();
++t3;
t3.show();
if(t2 == t3)
printf("OK..time out!\n");
#if 0
while(1)
{
t.addtimer(1);
t.show();
sleep(1);
}
#endif
}
1.2特殊运算符重载
#include <stdio.h>
#include <unistd.h>
class Timer{
public:
Timer()
{
hour = 0;
min = 0;
sec = 0;
}
~Timer()
{
}
void addtimer(int sec = 1)
{
this->min += (this->sec+sec)/60;
this->sec = (this->sec + sec) % 60;
}
void show()
{
printf("%2d:%2d:%2d\n", hour, min, sec);
}
Timer operator+(int sec)
{
Timer tem;
tem.sec = this->sec + sec;
return tem;
}
Timer operator+(Timer &x)
{
Timer tem;
tem.sec = sec + x.sec;
tem.min = min + x.min;
tem.hour = hour + x.hour;
return tem;
}
Timer operator++(int)
{
Timer tem = *this;
sec++;
return tem;
}
Timer operator++()
{
sec++;
return *this;
}
bool operator==(Timer &x)
{
if(sec == x.sec && min == x.min && hour == x.hour)
return true;
return false;
}
int operator[](int i)
{
switch(i)
{
case 0:
return hour;
case 1:
return min;
case 2:
return sec;
}
}
private:
int hour;
int min;
int sec;
};
int main()
{
Timer t;
t.addtimer(3);
Timer t1;
t1.addtimer(5);
Timer t2;
t2 = t + t1;
t2.show();
t2 = t2 + 5;
t2.show();
Timer t3 = t2++;
t3.show();
++t3;
t3.show();
if(t2 == t3)
printf("OK..time out!\n");
printf("hour: %d\n", t2[0]);
printf("min : %d\n", t2[1]);
printf("sec : %d\n", t2[2]);
#if 0
while(1)
{
t.addtimer(1);
t.show();
sleep(1);
}
#endif
}
如果返回的是对象就失去了左值的权利,(可以修改的值放到左边,所以左值就是修改值)
#include <stdio.h>
#include <unistd.h>
class Timer{
public:
Timer()
{
hour = 0;
min = 0;
sec = 0;
}
~Timer()
{
}
void addtimer(int sec = 1)
{
this->min += (this->sec+sec)/60;
this->sec = (this->sec + sec) % 60;
}
void show()
{
printf("%2d:%2d:%2d\n", hour, min, sec);
}
Timer operator+(int sec)
{
Timer tem;
tem.sec = this->sec + sec;
return tem;
}
Timer operator+(Timer &x)
{
Timer tem;
tem.sec = sec + x.sec;
tem.min = min + x.min;
tem.hour = hour + x.hour;
return tem;
}
Timer operator++(int)
{
Timer tem = *this;
sec++;
return tem;
}
Timer operator++()
{
sec++;
return *this;
}
bool operator==(Timer &x)
{
if(sec == x.sec && min == x.min && hour == x.hour)
return true;
return false;
}
int &operator[](int i)
{
switch(i)
{
case 0:
return hour;
case 1:
return min;
case 2:
return sec;
}
}
private:
int hour;
int min;
int sec;
};
int main()
{
Timer t;
t.addtimer(3);
Timer t1;
t1.addtimer(5);
Timer t2;
t2 = t + t1;
t2.show();
t2 = t2 + 5;
t2.show();
Timer t3 = t2++;
t3.show();
++t3;
t3.show();
if(t2 == t3)
printf("OK..time out!\n");
printf("hour: %d\n", t2[0]);
printf("min : %d\n", t2[1]);
printf("sec : %d\n", t2[2]);
t2[1] = 30;
printf("hour: %d\n", t2[0]);
printf("min : %d\n", t2[1]);
printf("sec : %d\n", t2[2]);
#if 0
while(1)
{
t.addtimer(1);
t.show();
sleep(1);
}
#endif
}
接下来我们看看拷贝中运算符重载的妙用
#include <stdio.h>
#include <string.h>
class A{
public:
A()
{
printf("A()\n");
p = new char[10];
strcpy(p, "hello");
printf("p: %s\n", p);
printf("p: %s\n", this->p);
}
A(const A &x)
{
printf("A(const A &x)\n");
p = new char[10];
strcpy(p, x.p);
}
~A()
{
printf("~A()\n");
delete [] p;
}
#if 0
A & operator=(A &x)
{
printf("operator=\n");
p = new char[10];
strcpy(p, x.p);
return *this;
}
#endif
private:
char *p;
};
int main()
{
A x;
A y = x;
y = x;
}
去掉注释部分
先学点快捷方式 3yy复制三行
接下来是()这里我们引出仿函数
#include <iostream>
using namespace std;
int main()
{
// std::cout<<"hello"<<std::endl;
cout<<"hello"<<endl;
}
#include <iostream>
using namespace std;
class Converter{
public:
Converter(double rate)
{
this->rate = rate;
}
double operator()(double rmb)
{
return rmb*rate;
}
private:
double rate;
};
double RMBto(double rmb, double rate)
{
return rmb*rate;
}
int main()
{
// std::cout << "hello"<<std::endl;
// cout << "hello"<<endl;
Converter RMBtoUS(6.4);
cout << RMBtoUS(10) << endl;
cout << RMBtoUS(10) << endl;
cout << RMBtoUS(10) << endl;
cout << RMBtoUS(10) << endl;
cout << RMBtoUS(10) << endl;
cout << RMBtoUS(10) << endl;
cout << RMBtoUS(10) << endl;
cout << RMBtoUS(10) << endl;
Converter RMBtoE(8.4);
cout << RMBtoE(100) << endl;
cout << RMBtoE(100) << endl;
cout << RMBtoE(100) << endl;
cout << RMBtoE(100) << endl;
cout << RMBtoE(100) << endl;
cout << RMBtoE(100) << endl;
#if 0
cout << RMBto(10, 6.4) << endl;
cout << RMBto(10, 6.4) << endl;
cout << RMBto(10, 6.4) << endl;
cout << RMBto(10, 6.4) << endl;
cout << RMBto(10, 6.4) << endl;
cout << RMBto(10, 6.4) << endl;
cout << RMBto(10, 6.4) << endl;
cout << RMBto(10, 6.4) << endl;
cout << RMBto(10, 6.4) << endl;
cout << RMBto(10, 6.4) << endl;
cout << RMBto(10, 6.4) << endl;
cout << RMBto(10, 6.4) << endl;
cout << RMBto(10, 6.4) << endl;
cout << RMBto(10, 8.4) << endl;
cout << RMBto(10, 8.4) << endl;
cout << RMBto(10, 8.4) << endl;
cout << RMBto(10, 8.4) << endl;
cout << RMBto(10, 8.4) << endl;
cout << RMBto(10, 8.4) << endl;
cout << RMBto(10, 8.4) << endl;
cout << RMBto(10, 8.4) << endl;
cout << RMBto(10, 8.4) << endl;
cout << RMBto(10, 8.4) << endl;
#endif
}
百度百科-验证
接下来是对输出运算符的重载
比如直接输出一个对象
#include <stdio.h>
#include <unistd.h>
#include <iostream>
using namespace std;
class Timer{
public:
Timer()
{
hour = 0;
min = 0;
sec = 0;
}
~Timer()
{
}
void addtimer(int sec = 1)
{
this->min += (this->sec+sec)/60;
this->sec = (this->sec + sec) % 60;
}
void show()
{
printf("%2d:%2d:%2d\n", hour, min, sec);
}
Timer operator+(int sec)
{
Timer tem;
tem.sec = this->sec + sec;
return tem;
}
Timer operator+(Timer &x)
{
Timer tem;
tem.sec = sec + x.sec;
tem.min = min + x.min;
tem.hour = hour + x.hour;
return tem;
}
Timer operator++(int)
{
Timer tem = *this;
sec++;
return tem;
}
Timer operator++()
{
sec++;
return *this;
}
bool operator==(Timer &x)
{
if(sec == x.sec && min == x.min && hour == x.hour)
return true;
return false;
}
int &operator[](int i)
{
switch(i)
{
case 0:
return hour;
case 1:
return min;
case 2:
return sec;
}
}
friend ostream &operator<<(ostream &out, const Timer &t);
private:
int hour;
int min;
int sec;
};
ostream &operator<<(ostream &out, const Timer &t)
{
out << "hour:" << t.hour << "min:" <<t.min<<"sec:" <<t.sec<<endl;
}
int main()
{
Timer t;
t.addtimer(3);
Timer t1;
t1.addtimer(5);
Timer t2;
t2 = t + t1;
t2.show();
t2 = t2 + 5;
t2.show();
Timer t3 = t2++;
t3.show();
++t3;
t3.show();
if(t2 == t3)
printf("OK..time out!\n");
printf("hour: %d\n", t2[0]);
printf("min : %d\n", t2[1]);
printf("sec : %d\n", t2[2]);
t2[1] = 30;
printf("hour: %d\n", t2[0]);
printf("min : %d\n", t2[1]);
printf("sec : %d\n", t2[2]);
cout<<t2;
#if 0
while(1)
{
t.addtimer(1);
t.show();
sleep(1);
}
#endif
}
二、标准输入输出流
#include <stdio.h>
#include <iostream>
using namespace std;
int main()
{
//printf("input:");fflush(stdout);
cout<<"input:";
char buf[100];
//gets(buf);
cin >> buf;
//printf("%s\n", buf);
cout << buf <<endl;
}
它会自动识别,不像C那样%d %s %C 什么的
#include <stdio.h>
#include <iostream>
using namespace std;
int main()
{
//printf("input:");fflush(stdout);
cout<<"input:";
char buf[100];
//gets(buf);
cin >> buf;
//printf("%s\n", buf);
cout << buf <<endl;
cout<<10<<endl;
cout <<hex<<10<<endl;
}
控制符 | 作 用 |
dec | 设置数值的基数为10 |
hex | 设置数值的基数为16 |
oct | 设置数值的基数为8 |
setfill(c) | 设置填充字符c,c可以是字符常量或字符变量 |
setprecision(n) | 设置浮点数的精度为n位。在以一般十进制小数形式输出时,n代表有效数字。在以fixed(固定小数位数)形式和 scientific(指数)形式输出时,n为小数位数 |
setw(n) | 设置字段宽度为n位 |
setiosflags( ios::fixed) | 设置浮点数以固定的小数位数显示 |
setiosftags( ios::scientific) | 设置浮点数以科学记数法(即指数形式)显示 |
setiosflags( ios::left) | 输出数据左对齐 |
setiosflags( ios::right) | 输出数据右对齐 |
setiosflags( ios::skipws) | 忽略前导的空格 |
setiosflags( ios::uppercase) | 数据以十六进制形式输出时字母以大写表示 |
setiosflags( ios::lowercase) | 数据以十六进制形式输出时宇母以小写表示 |
setiosflags(ios::showpos) | 输出正数时给出“+”号 |
需要注意的是: 如果使用了控制符,在程序单位的开头除了要加iostream头文件外,还要加iomanip头文件。
流成员函数 | 与之作用相同的控制符 | 作用 |
precision(n) | setprecision(n) | 设置实数的精度为n位 |
width(n) | setw(n) | 设置字段宽度为n位 |
fill(c) | setfill(c) | 设置填充宇符c |
setf() | setiosflags() | 设置输出格式状态,括号中应给出格式状态,内容与控制符setiosflags括号中的内容相同,如表13.5所示 |
unsetf() | resetioflags() | 终止已设置的输出格式状态,在括号中应指定内容 |
格式标志 | 作用 |
ios::left | 输出数据在本域宽范围内向左对齐 |
ios::right | 输出数据在本域宽范围内向右对齐 |
ios::internal | 数值的符号位在域宽内左对齐,数值右对齐,中间由填充字符填充 |
ios::dec | 设置整数的基数为10 |
ios::oct | 设置整数的基数为8 |
ios::hex | 设置整数的基数为16 |
ios::showbase | 强制输出整数的基数(八进制数以0打头,十六进制数以0x打头) |
ios::showpoint | 强制输出浮点数的小点和尾数0 |
ios::uppercase | 在以科学记数法格式E和以十六进制输出字母时以大写表示 |
ios::showpos | 对正数显示“+”号 |
ios::scientific | 浮点数以科学记数法格式输出 |
ios::fixed | 浮点数以定点格式(小数形式)输出 |
ios::unitbuf | 每次输出之后刷新所有的流 |
ios::stdio | 每次输出之后清除stdout, stderr |
三、组合与继承
3.1组合
一个类的功能都是依据另一个类的对象实现的,就是组合。
3.2继承
#include <iostream>
using namespace std;
class A{
public:
A(){ }
~A(){ }
void showx()
{
cout<<"xxxxxxxxxxxxxxxxxxx"<<endl;
}
};
class AX:public A{
public:
void showy()
{
cout << "yyyyyyyyyyyyyyyyyyyyyyyyy"<<endl;
}
};
int main()
{
A a;
a.showx();
AX b;
b.showx();
b.showy();
}
然后再回到我们想写的学生管理系统,我们想要再加一个求平均值的功能,那么前面那种组合的方式就不能满足了。
#include "arr.h"
#include <iostream>
using namespace std;
class ARRX:public ARR{
public:
int ever(void)
{
int i = 0;
int sum = 0;
for(;i<tail; i++)
sum += data[i];
return sum/tail;
}
};
class Stuma{
public:
Stuma(){
}
~Stuma() { }
void savescore(int score)
{
scorearr.addtail(score);
}
int everscore(void)
{
return scorearr.ever();
}
void showscore(void)
{
scorearr.show();
}
private:
//ARR scorearr;
ARRX scorearr;
};
int main()
{
Stuma mmm;
mmm.savescore(23);
mmm.savescore(44);
mmm.savescore(55);
mmm.savescore(23);
mmm.showscore();
cout << mmm.everscore() <<endl;
}
1) public继承方式
- 基类中所有public成员在派生类中为public属性;
- 基类中所有protected成员在派生类中为protected属性;
- 基类中所有private成员在派生类中不可访问。
2) protected继承方式
- 基类中的所有public成员在派生类中为protected属性;
- 基类中的所有protected成员在派生类中为protected属性;
- 基类中的所有private成员在派生类中仍然不可访问。
3) private继承方式
- 基类中的所有public成员在派生类中均为private属性;
- 基类中的所有protected成员在派生类中均为private属性;
- 基类中的所有private成员在派生类中均不可访问。
小作业:模仿c++的string类,自己实现string类
百度百科-验证
能够准确无误地编写出String类的构造函数、拷贝构造函数、赋值函数和析构函数的面试者至少已经具备了C++基本功的60%以上!在这个类中包括了指针类成员变量m_data,当类中包括指针类成员变量时,一定要重载其拷贝构造函数、赋值函数和析构函数,这既是对C++程序员的基本要求,也是《Effective C++》中特别强调的条款。仔细学习这个类,特别注意加注释的得分点和加分点的意义,这样就具备了60%以上的C++基本功!
我暂时不需要会这么多,就按会60%的标准写这四个,看了两个大佬写的比较全,连接放这,需要的自己去看看:
模拟实现C++中的string类(详细解析)_二肥是只大懒蓝猫的博客-CSDN博客
C++ string类模拟实现_全貌的博客-CSDN博客_模仿c++的string类,自己实现string类
#include <stddef.h>
#include <algorithm>
#include <iostream>
#include <string.h>
//using namespace std;
class String{
public:
String()
{
_str = new char[1];
_size = 0;
_capacity = 0;
_str[0] = '\0';
}
String(char* str)
{
_size = strlen(str);
_capacity = _size;
_str = new char[_capacity + 1];
strcpy(_str, str);
}
~String()
{
delete[] _str;
_size = 0;
_capacity = 0;
}
void swap(String& tmp)
//这是自己定义的交换函数,第一个参数是隐含的this指针,交换两个类的成员变量
{
std::swap(_str, tmp._str);//加::操作符表示调用的是全局的swap函数
//_str和tmp._str都是指针,交换指向的空间的地址
std::swap(_size, tmp._size);
std::swap(_capacity, tmp._capacity);
}
//拷贝构造的传统写法
String(String& s)
{
_str = new char[s._capacity + 1];
_capacity = s._capacity;
_size = s._size;
strcpy(_str, s._str);
}
String& operator=(String& s)
//使用传值传参,调用拷贝构造创建临时类s接收需要赋值的string类
{
if (this != &s)
{
String tmp(s);
swap(s);//交换它们
}
return *this;//返回this指向的类
}//结束时临时类s销毁,自动调用析构函数
private:
char* _str;
size_t _size; //long long unsigned int
size_t _capacity;
};
int main()
{
}