C++高级语法
面向对象 – 类/结构体
- C++使用class定义一个类,使用struct定义一个结构体
struct的默认成员权限是public,class的默认成员权限是private,除此之外二者基本没有差别。
抽象-具体类型
- 让自定义类型的类像内置类型一样
封装和函数重载示例:
Complex.h
#include <iostream>
using namespace std;
class Complex
{
public:
Complex(); // 默认构造函数
Complex(double r, double i); // 构造函数
virtual ~Complex(); // 析构函数
Complex(const Complex& x); // 拷贝构造
Complex& operator=(const Complex &c); // =号运算符
double GetReal( ) const { return _real; }
void SetReal(double d) { _real = d; }
double GetImage() const { return _image; }
void SetImage(double i) { _image = i; }
// 运算符重载
Complex operator+(const Complex &c) const;
Complex& operator+=(const Complex &c);
Complex operator-(const Complex &c) const;
Complex& operator-=(const Complex &c);
Complex operator*(const Complex &c) const;
Complex& operator*=(const Complex &c);
Complex operator/(const Complex &c) const;
Complex& operator/=(const Complex &c);
bool operator==(const Complex &c) const;
bool operator!=(const Complex &c) const;
bool operator>(const Complex &c) const;
bool operator>=(const Complex &c) const;
bool operator<(const Complex &c) const;
bool operator<=(const Complex &c) const;
// 前置和后置++
Complex& operator++(); //前置++
Complex operator++(int); //后置++
Complex& operator--(); //前置--
Complex operator--(int); //后置--
//protected:
friend ostream& operator<<(ostream& os, const Complex &x);
friend istream& operator>>(istream& is, Complex &x);
private:
double _real; // 复数的实部
double _image; // 复数的虚部
};
Complex.cpp
#include "Complex.h"
Complex::Complex()
{
_real = 0.0;
_image = 0.0;
//cout << "Complex::Complex()" << endl;
}
Complex::Complex(double r, double i)
{
_real = r;
_image = i;
//cout << "Complex::Complex(double r, double i)" << endl;
}
Complex::Complex(const Complex& c)
{
_real = c._real;
_image = c._image;
//cout << "Complex::Complex(const Complex& c)" << endl;
}
Complex& Complex::operator= (const Complex& c)
{
if (this != &c)
{
_real = c._real;
_image = c._image;
}
return *this;
}
Complex::~Complex()
{
_real = _image = 0.0;
//cout << "Complex::~Complex()" << endl;
}
Complex Complex::operator+ (const Complex& c) const
{
//Complex tmp;
//tmp._real = _real + x._real;
//tmp._image = _image + x._image;
//return tmp;
return Complex(_real + c._real, _image + c._image);
}
Complex& Complex::operator+= (const Complex& c)
{
_real += c._real;
_image += c._image;
return *this;
}
Complex Complex::operator-(const Complex &c) const
{
return Complex(_real - c._real, _image - c._image);
}
Complex& Complex::operator-=(const Complex &c)
{
_real -= c._real;
_image -= c._image;
return *this;
}
Complex Complex::operator*(const Complex &c) const
{
return Complex(_real*c._real - _image*c._image, _real*c._image + _image*c._real);
}
Complex& Complex::operator*=(const Complex &c)
{
Complex tmp(*this); //拷贝构造函数
_real = tmp._real*c._real - _image*c._image;
_image = tmp._real*c._image + tmp._image*c._real;
return *this;
}
Complex Complex::operator/(const Complex &c) const
{
double t = c._real*c._real + c._image*c._image;
return Complex((_real*c._real - _image*(-c._image)) / t, (_real*(-c._image) + _image*c._real) / t);
}
Complex& Complex::operator/=(const Complex &c)
{
Complex tmp(*this); //拷贝构造函数
double t = c._real*c._real + c._image*c._image;
_real = (tmp._real*c._real - tmp._image*(-c._image)) / t;
_image = (tmp._real*(-c._image) + tmp._image*c._real) / t;
return *this;
}
bool Complex::operator==(const Complex& c) const
{
return (_real == c._real) && (_image == c._image);
}
bool Complex::operator!=(const Complex& c) const
{
return !( (_real == c._real) && (_image == c._image) );
}
bool Complex::operator>(const Complex &c) const
{
return (_real > c._real) && (_image > c._image);
}
bool Complex::operator>=(const Complex &c) const
{
return (_real >= c._real) && (_image >= c._image);
}
bool Complex::operator<(const Complex &c) const
{
return (_real < c._real) && (_image < c._image);
}
bool Complex::operator<=(const Complex &c) const
{
return (_real <= c._real) && (_image <= c._image);
}
Complex& Complex::operator++ () // 前置++
{
_real++;
_image++;
return *this;
}
Complex Complex::operator++ (int) // 后置++
{
//Complex tmp(*this);
//_real++;
//_image++;
//return tmp;
return Complex(_real++, _image++);
}
Complex& Complex::operator--() //前置--
{
_real--;
_image--;
return *this;
}
Complex Complex::operator--(int) //后置--
{
return Complex(_real--, _image--);
}
ostream& operator<<(ostream& os, const Complex &x)
{
os << "real value is " << x._real << " image value is " << x._image;
return os;
}
istream& operator >> (istream& is, Complex &x)
{
is >> x._real >> x._image;
return is;
}
标准I/O流
I/O流
-
传统C中的I/O流有printf,scanf,getch,gets等函数:他们的问题是:
- 不可编程,仅仅能识别固有数据类型
1. 代码可移植性差,有很多坑
- 不可编程,仅仅能识别固有数据类型
-
C++中的I/O流istream,ostream等:
- 可编程,对于使用类库的设计者来说很有用
- 简化编程,使得I/O风格一致
I/O缓存区
- 标准IO提供三种类型的缓存模式
- 按块缓存:如文件系统
- 按行缓存:\n
- 不缓存。
文件操作
- 输入流的七点和输出流的终点都可以是磁盘文件
- 文件:C++把每个文件都看成是一个有序的字节序列,每个文件都是以文件结束标志结束
- 按照文件中的数据的组织形式可以把文件分成:
- 文本文件:文件中信息形式为ASCII码文件,每个字符占一个字节
- 二进制文件:文件中信息的形式与其在内存中的形式相同
文件操作步骤:
- 打开文件用于读和写 open;
- 检查是否打开成功 fail;
- 读或者写操作;
- 检查是否读完EOF;
- 使用完成之后关闭文件;
文件的打开方式:
方式 | 描述 |
---|---|
ios::in | 打开文件进行读操作 |
ios::out | 打开文件进行写操作 |
ios::ate | 打开一个已有输入或者输出文件并查找文件结尾 |
ios::app | 打开文件以便在文件尾部添加数据 |
ios::nocreate | 如果文件不存在则打开失败 |
ios::trunc | 如果文件存在,清除文件内容 |
ios::binary | 以二进制形式打开 |
#include <string>
#include <fstream>
#include <iostream>
using namespace std;
static const int bufferLen = 2048;
bool CopyFile(const string& src, const string& dst)
{
// 打开源文件和目标文件
// 源文件以二进制读的方式打开
// 目标文件以二进制写的方式打开
ifstream in(src.c_str(), ios::in | ios::binary);
ofstream out(dst.c_str(), ios::out | ios::binary | ios::trunc);
// 判断文件打开是否成功,失败返回false
if (!in || !out)
{
return false;
}
// 从源文件中读取数据,写到目标文件中
// 通过读取源文件的EOF来判断读写是否结束
char temp[bufferLen];
while (!in.eof())
{
in.read(temp, bufferLen);
streamsize count = in.gcount();
out.write(temp, count);
}
// 关闭源文件和目标文件
in.close();
out.close();
return true;
}
int main()
{
cout << CopyFile("Blue Daube.mp3", "Blue Daube2.mp3") << endl;
//int a;
//int index = 0;
//fstream fout;
//fout.open("testBuffer.txt", ios::app);
if (fout.fail())
//if (!fout)
//{
// cout << "open file failed" << endl;
//}
//while (cin >> a)
//{
// //cout << "The numbers are: " << a << endl;
// fout << "The numbers are: " << a << endl;
// index++;
// if (index == 5)
// {
// break;
// }
//}
//cin.ignore(numeric_limits<std::streamsize>::max(), '\n'); // 清空缓存区脏数据
//char ch;
//cin >> ch;
cout << "the last char is: " << ch << endl;
//fout << "the last char is: " << ch << endl;
//fout.close();
return 0;
}
头文件的重复包含问题
-
为了避免同一个文件被多次include ,有两种方式
-
#ifndef aa #define aa #endif
使用宏来方式同一个文件被多次包含
优点:可移植性好
缺点:无法防止宏名称重复,难以排查错误
-
#program once
使用编译器来防止同一个文件被多次包含
优点:可以防止宏名重复,易排错
缺点:可移植性不好
-
深拷贝和浅拷贝,写时复制
- 浅拷贝:只拷贝指针地址,C++默认拷贝构造函数与赋值运算符都是浅拷贝,节省空间,但是容易引发多次释放;
- 深拷贝:重新分配堆内存,拷贝指针指向内容。浪费空间,但不会导致多次释放;
如何同时具备二者的优点?
- 使用引用计数
- C++新标准的移动语义
String.h
#pragma once
class String
{
public:
String(const char *str = NULL); // 普通构造函数
String(const String &other); // 拷贝构造函数
String(String&& other); // 移动构造函数
~String(void); // 析构函数
String& operator= (const String& other); // 赋值函数
String& operator=(String&& rhs)noexcept; // 移动赋值运算符
friend ostream& operator<<(ostream& os, const String &c); // cout输出
private:
char *m_data; // 用于保存字符串
};
String.cpp
#include "stdafx.h"
// _CRT_SECURE_NO_WARNINGS
// String 的普通构造函数
String::String(const char *str)
{
if (str == NULL)
{
m_data = new char[1];
if (m_data != NULL)
{
*m_data = '\0';
}
else
{
exit(-1);
}
}
else
{
int len = strlen(str);
m_data = new char[len + 1];
if (m_data != NULL)
{
strcpy(m_data, str);
}
else
{
exit(-1);
}
}
}
// 拷贝构造函数
String::String(const String &other)
{
int len = strlen(other.m_data);
m_data = new char[len + 1];
if (m_data != NULL)
{
strcpy(m_data, other.m_data);
}
else
{
exit(-1);
}
}
// 移动构造函数
String::String(String&& other)
{
if (other.m_data != NULL)
{
// 资源让渡
m_data = other.m_data;
other.m_data = NULL;
}
}
// 赋值函数
String& String::operator= (const String &other)
{
if (this == &other)
{
return *this;
}
// 释放原有的内容
delete[ ] m_data;
// 重新分配资源并赋值
int len = strlen(other.m_data);
m_data = new char[len + 1];
if (m_data != NULL)
{
strcpy(m_data, other.m_data);
}
else
{
exit(-1);
}
return *this;
}
// 移动赋值运算符
String& String::operator=(String&& rhs)noexcept
{
if(this != &rhs)
{
delete[] m_data;
m_data = rhs.m_data;
rhs.m_data = NULL;
}
return *this;
}
// String 的析构函数
String::~String(void)
{
if (m_data != NULL)
{
delete[] m_data;
}
}
ostream& operator<<(ostream& os, const String &c)
{
os << c.m_data;
return os;
}
main.cpp
int main()
{
String s1("Hello"); // 构造函数
cout << s1 << endl;
//String s2 = s1; // 调用拷贝构造函数
String s2(s1); // 调用拷贝构造函数
cout << s2 << endl;
String s2A(std::move(s1)); // 移动构造函数
cout << s2A << endl;
String s3; // 无参构造函数
cout << s3 << endl;
s3 = s2; // 调用赋值函数
cout << s3 << endl;
String s3A; // 无参构造函数
s3A = std::move(s2A); // 移动赋值运算符
cout << s3A << endl;
return 0;
}
面向对象的三大特性
- 封装性:数据和代码捆绑在一起,避免外界干扰和不确定性访问,封装可以使得代码模块化
- 继承性:让某种类型对象获得另一个类型对象的属性和方法,继承可以扩展已存在的代码
- 多态性:同一事物表现出不同事物的能力,即面向不同的对象产生不同的行为,多态的目的是为了接口重用
面向对象是什么
- 面向对象是软件工程发展到一定的阶段为了管理代码和数据提出的一种方法,它没有解决以前解决不了的问题,不是万能的
- 面向对象不是对现实世界的映射,但他的封装性可以把问题简化,便于抽象;它的多台可以减少代码重复,避免重新发明轮子;它的多台可以实现灵活的功能扩展,提升开发效率
- 面向对象为我们便捷开发出能适应软件变化的软件提供了可能