C++高级语法

简介: ● C++使用class定义一个类,使用struct定义一个结构体struct的默认成员权限是public,class的默认成员权限是private,除此之外二者基本没有差别。

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.不可编程,仅仅能识别固有数据类型

 1. 代码可移植性差,有很多坑

●  C++中的I/O流istream,ostream等:


 1.可编程,对于使用类库的设计者来说很有用

 2.简化编程,使得I/O风格一致


I/O缓存区

●  标准IO提供三种类型的缓存模式

  • 按块缓存:如文件系统
  • 按行缓存:\n
  • 不缓存。


文件操作

●  输入流的七点和输出流的终点都可以是磁盘文件

●  文件:C++把每个文件都看成是一个有序的字节序列,每个文件都是以文件结束标志结束

●  按照文件中的数据的组织形式可以把文件分成:

   ○  文本文件:文件中信息形式为ASCII码文件,每个字符占一个字节

   ○  二进制文件:文件中信息的形式与其在内存中的形式相同


文件操作步骤:


1.打开文件用于读和写 open;

2.检查是否打开成功 fail;

3.读或者写操作;

4.检查是否读完EOF;

5.使用完成之后关闭文件;


文件的打开方式:

方式 描述
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;
}

面向对象的三大特性

 ●  封装性:数据和代码捆绑在一起,避免外界干扰和不确定性访问,封装可以使得代码模块化

 ●  继承性:让某种类型对象获得另一个类型对象的属性和方法,继承可以扩展已存在的代码

 ●  多态性:同一事物表现出不同事物的能力,即面向不同的对象产生不同的行为,多态的目的是为了接口重用


面向对象是什么

 ●  面向对象是软件工程发展到一定的阶段为了管理代码和数据提出的一种方法,它没有解决以前解决不了的问题,不是万能的

 ●  面向对象不是对现实世界的映射,但他的封装性可以把问题简化,便于抽象;它的多台可以减少代码重复,避免重新发明轮子;它的多台可以实现灵活的功能扩展,提升开发效率

 ●  面向对象为我们便捷开发出能适应软件变化的软件提供了可能

目录
相关文章
|
2月前
|
Java C# C++
C++ 11新特性之语法甜点1
C++ 11新特性之语法甜点1
31 4
|
2月前
|
编译器 C++ 容器
C++ 11新特性之语法甜点2
C++ 11新特性之语法甜点2
29 1
|
2月前
|
存储 算法 编译器
C++ 11新特性之语法甜点4
C++ 11新特性之语法甜点4
27 0
|
2月前
|
安全 C++ 容器
C++ 11新特性之语法甜点3
C++ 11新特性之语法甜点3
35 0
|
3月前
|
编译器 C++ 容器
C++语言的基本语法
想掌握一门编程语言,第一步就是需要熟悉基本的环境,然后就是最重要的语法知识。 C++ 程序可以定义为对象的集合,这些对象通过调用彼此的方法进行交互。现在让我们简要地看一下什么是类、对象,方法、即时变量。 对象 - 对象具有状态和行为。例如:一只狗的状态 - 颜色、名称、品种,行为 - 摇动、叫唤、吃。对象是类的实例。 类 - 类可以定义为描述对象行为/状态的模板/蓝图。 方法 - 从基本上说,一个方法表示一种行为。一个类可以包含多个方法。可以在方法中写入逻辑、操作数据以及执行所有的动作。 即时变量 - 每个对象都有其独特的即时变量。对象的状态是由这些即时变量的值创建的。 完整关键字
|
4月前
|
Java 编译器 程序员
C++中的语法知识虚继承和虚基类
**C++中的多继承可能导致命名冲突和数据冗余,尤其在菱形继承中。为解决这一问题,C++引入了虚继承(virtual inheritance),确保派生类只保留虚基类的一份实例,消除二义性。虚继承通过`virtual`关键字指定,允许明确访问特定路径上的成员,如`B::m_a`或`C::m_a`。这样,即使基类在继承链中多次出现,也只有一份成员副本,简化了内存布局并避免冲突。虚继承应在需要时提前在继承声明中指定,影响到从虚基类派生的所有后代类。**
|
4月前
|
编译器 C++ 开发者
C++一分钟之-属性(attributes)与属性语法
【7月更文挑战第3天】C++的属性(attributes)自C++11起允许附加编译器指令,如`[[nodiscard]]`和`[[maybe_unused]]`,影响优化和警告。注意属性放置、兼容性和适度使用,以确保代码清晰和可移植。示例展示了如何使用属性来提示编译器处理返回值和未使用变量,以及利用编译器扩展进行自动清理。属性是提升代码质量的工具,但应谨慎使用。
131 13
|
5月前
|
编译器 程序员 C++
C++一分钟之-属性(attributed)与属性语法
【6月更文挑战第28天】C++的属性为代码添加元数据,帮助编译器理解意图。C++11引入属性语法`[[attribute]]`,但支持取决于编译器。常见属性如`nodiscard`提示检查返回值,`maybe_unused`防止未使用警告。问题包括兼容性、过度依赖和误用。使用属性时需谨慎,确保团队共识,适时更新以适应C++新特性。通过示例展示了`nodiscard`和`likely/unlikely`的用法,强调正确使用属性能提升代码质量和性能。
80 13
|
5月前
|
编译器 C语言 C++
|
5月前
|
Linux C++
c++高级篇(三) ——Linux下IO多路复用之poll模型
c++高级篇(三) ——Linux下IO多路复用之poll模型