软件设计II模板整理_C++面向对象编程

6.11更新

因为没有人来cording hub..所以丢回github了
顺便搭了一个博客更新放在这了

6.2已经更新

整理了原来乱七八糟的框架结构
删除了参考模板
模拟考试前会更新~
考试前会出便于打印版本~

这是一个开源项目

希望懂一点点git和markdown的同学能参与进来

  • 因为coding是中文网站,界面比较友好便放在那里了
    和github使用对比只是没有命令行操作吧..
    其实主要就是上传/修改文件到分支

markdown学习笔记
git参考教程

项目地址

点进去下载w

在这个地址里面的版本较新,完成较好后或会整理便于打印的版本

软件设计II模板

leidar100@gmail.com

  • 类函数的实现implementation

    有些题目往往给出了类的声明,要求完成实现.其实也就是在类外写一个函数

    函数名前面加上类名

    class seriesComp{
        seriesComp(int n);
        int sum();
    }
    //返回类型不用改变,参数名不用改变,只要在函数名前加类名
    seriesComp::seriesComp(int n)
    {
    // your code
    }//构造就不用返回
    int seriesComp::sum() {
    // your code
    }//该返回int就返回int
    //和上面等价的实现
    class seriesComp{
        seriesComp(int n){
        // your code1
    }
        int sum(){
        // your code2
    }
    }

构造函数

  • 初始化成员变量

    1. this指针

      //常见于构造函数,区分与传入参量的相同名字
      Date::Date(int year, int month)
      {
       this->year =year;           //可调用属性
      this->month=month;
       this->pass =this->validate();//可调用方法
      }
    2. 成员初始化器

      //在构造函数里面,即使和传入名相同(同上)
      Date::Date(int year, int month)
      :year(year),month(month)     //用逗号分开
      {
       this->pass =this->validate();//可调用方法
      }
    3. 对于指针分配新的内存空间=>数组

      //new char[长度]  char可以换成别的类型或者模板T
      
    4. 更新static计数器数目

    5. 调用Setter更新

  • 拷贝构造函数

    1. 关键在于加&传引用*,不然会无限递归

    2. 深拷贝(当传入一个数组时候需要考虑,直接赋值仅仅改变了指针方向)

      String::String(const String& b){
       str=new char[strlen(b.str)+1];//#include <cstring>,动态分配内存空间
       int pos;
       for (pos=0; b.str[pos]!='\0'; pos++) 
           str[pos]=b.str[pos];
       str[pos]='\0';//字符串最后一位记得加'\0'
      }

析构函数(RAII)

  • 长相

    • 没有返回值,没有参数
    • 函数名前加~:ClassName
  • 清理动态(new)分配的内存空间

  • 可能与static参量相关,析构时候-1

    MyString::~MyString(){
      MyString::numberOfObjects--;//如果有计数器的话
      delete str;//删除没有被分配空间的指针时候会CE
    }

  • 在出了代码块或者使用delete时候调用

Getter & Setter

  • 为了实现类的封装(从外界装逼地修改private数据),于是出现了Getter个setter

    这样就可以象征性的保护类中的数据和方法

  • Getter模板

    int Date::getYear() const
    {
      return year;//一般直接返回,但是在重载数组[]的时候如果认为是getter可能检查下标
    }
  • Setter模板

    与Getter不同的是,往往需要检查传入数据的合法性

    void Date::setDate(const string& input)
    {
      if (checkFormat(input))
      {
          istringstream trans(input);
          char temp;
          trans >> year >> temp >> month >> temp >> day;
      }//检查数据合法性
        else
          year=month=day=233;
      pass=validate();
    }

运算符重载

  1. 其实就是把函数名换成了运算符
  2. 一般而言会遵循使用习惯返回值,比如+=返回当前对象,==返回bool值
  3. +=+, ==!=都需要分开重载,+,-是重载正负运算符
  4. 很多STL使用需要重载<运算符,比如set,map,优先队列

    • 普通运算符重载(参考lab06)
    返回类型 运算符operator(符号名) (参数列表)
    {
    函数体  
    }
    /*hw05
    返回类型:Complex对象
    符号名:+
    因为是对类的方法的实现,所以要加作用域符号Complex::
    参数列表: 另一个Complex
    */
    Complex Complex::operator+(Complex&com)
    {
      Complex ans(real+com.real,imag+com.imag);
      return ans;
    }
    • 流(左移右移运算符)重载记得加&

    可参考这篇题解更深入理解<<运算符的重载

    因为是在外界调用,需要声明为友元函数

    //一般输入输出流的重载
    //按照自己意愿输出,使用和cin,cout类似
    ostream& operator<<(ostream& os, Complex& com){
      //这里给os输出一些东西 os << something
      return os;//返回流
    }
    
    //overload `>>` operator按照自己意愿输入
    istream& operator>>(istream& os, Complex& com){
      os>>com.real>>com.imag;
      return os;//返回流
    }
    • 取位运算符重载
    /*
    返回类型: double
    符号名 :  [] //重载这个运算符往往要注意位置是否合法
    参数列表: int
    */
    double& Complex::operator[](int i){
      if (i==0) {
          return real;
      }else
          return imag;
    }
    • 赋值运算符重载(或涉及深拷贝)
    /*
    返回类型: 类的对象,这里是String
    符号名 :  =  //重载这个运算符往往要注意位置是否合法
    参数列表: 任意参数,这里是char,也可以是string
    */
    String& String::operator=(const char *b){
      str=new char[strlen(b)+1];
      int pos;
      for (pos=0; b[pos]!='\0'; pos++) 
          str[pos]=b[pos];
      str[pos]='\0';
      return *this;
    }
    /*判断是否为当前,lab07*/
    const MyVector & MyVector::operator=(const MyVector &vec){
    if(*this==vec)return *this;
        delete []elem;
      int len = vec._size;
      elem = new Elements[len];
      for (int i=0; i<len; i++) 
          elem[i]=vec.elem[i];
      _size=len;
      return *this;
    };//assignment
    
    • ++ --
    // Define function operators for prefix ++ and --
    Rational& Rational::operator++(){
      numerator += denominator;
      return *this;//前缀++,可以直接把当前加一,然后返回当前
    }
    
    // Define function operators for postfix ++ and --
    
    Rational Rational::operator++(int dummy){
      Rational old = *this;
      numerator += denominator;
      return old;//后缀++,记得有dummy值,返回以前的值
    }

    • 类型转换运算符
    Rational::operator double(){
    return ((double)numerator/denominator);
    }//没有标明返回值但是需要返回

static

其实我觉得static就是类里面的“全局变量”,类中static函数+static变量相当于在面向过程的普通函数+全局变量 -by第三周实验报告

  • static成员变量需要在类外面初始化为0(lab05)

    //内部-模板
    class MyString
    {
    public:
    ...
        static int getNumberOfObjects();
    private:
    ...
      static int numberOfObjects;             //counter    
    };
    //外部-格式:类型 类名::变量名=初始值;
    int MyString::numberOfObjects=0;//necessary declare but '=0' not necessary
    
    int MyString::getNumberOfObjects(){
    return numberOfObjects;
    }//照样要加MyString::也就是类名

  • 不能被this指代

    • 应用 对象数目统计
    //构造函数+1
    MyString::MyString(int Length, char sym)
    {
        numberOfObjects++;//这里
        str = new char[Length+1];
        fill(str, str+Length, sym);//fill is an interestiong function
        str[Length]='\0';
    }
    //析构函数-1
    MyString::~MyString(){
        MyString::numberOfObjects--;
        delete str;
    }

两个类的has关系

  • 其实c++中int也是一个类,char也是一个类,只不过是语言自带的
  • 所以包含int a;和包含MyClass a层次上面是等价的..所以包含就行(见lab5)

两个类的is关系(继承)

  • 基本模型

    //在头文件中include父类的头文件
    class derived:father{
    //它的新方法和属性
    }
  • 这样就可以

    1. 拥有父类的所有东西
    2. 使用父类publicprotected可见度的方法
    3. 被父类指针指向
  • virtual 函数

    • 在父类里面函数前加virtual,子类里面实现
    • 指向子类的指针就会使用子类里面的实现
    • 纯虚构函数
    • virtual 返回值 函数名(参数列表) = 0;
    • 必须在子类实现,没有父类对象
    • virtual void withdraw(double) = 0;
    • 一般析构函数都声明为virtual

其它内容

文件流

这篇博客是一个文件流OJ的入门

  • 就是创造一个类似于cin,cout的东西
//输入流_1
#include <fstream>
ifstream fin("in.txt");
fin.close();
//输入流_2
#include <fstream>
ifstream fin;
fin.open("in.txt");
fin.close();
//另外读入string文件名的话可以用.c_str()转化为字符串
//输出流
#include <ofstream>
ofstream fout("out.txt");
fout.close();
  • 另外想舒服正常一些操作的话有下面两种方法

    1. 不include\ 起名为cin,cout

    2. 重定向流输入输出

      
      #include <cstdio>
      
      freopen("telecow.in", "r", stdin);
      freopen("telecow.out", "w", stdout); 
  • 其它流运算符hex, fixed(保留小数),showpoint,setprecision(n)

  • 流标志符eof()

sstream

  • 流对象,stringstream str(Str);
  • 可以使用>>,<<来往这个流内输入输出

模板类/函数

在函数/类前面加上

template <typename T, int capacity>//第二个是容量参数,可以用来声明数组长度

或者

template <class T>

  • 构造函数(举个例子)

    template <typename T, int capacity> //类前需要加上
    class Stack
    {
    public:
      Stack();                   // Constructs an empty stack.
    private:
      T* elements;                  // Points to an array that stores elements in the stack.
    };
    template <typename T, int capacity>   //每一个函数前都得加上
    Stack<T,capacity>::Stack()
    {
      elements = new T[capacity];
    }                   // Constructs an empty stack.
  • 使用的时候参考STL中vector使用

  • 另外这个的头文件和实现不能分成两个文件

  • 模板测试函数

    template <class T>
    void TEST(Array<T,MAXLEN> &theArray,
            T FirstValue,T increment)
    {}

异常

在一段可能除0,可能越界,可能干坏事的代码块前加上try

出现坏事throw一个对象

catch根据对象类别 选择措施

//基本模型
template <typename T, int capacity>
T& Array<T,capacity>::operator[] (int index)
{
    try {
        if (index < 0 || index >= num)
        {
            throw ArrayException("Out of Range Exception");
        }//illegal index
    }
    catch (int a){};
    return elements[index];
}
  • 异常类模板
//异常类就是专门一个类,throw这个类的一个对象
class ArrayException
{

public:

    ArrayException(const char *msg);

    const char *what() const;//约定俗成的名字

private:

    const char *message;

};

lab04

对象数组 就是对于数组指针和移位的练习,有趣的是迭代器不能+1来实现指针的移位

  • RAII

    析构了一个值之后又要重新使用那个值

    于是就拿另一个指针来存那个值

    while (cin >> value)
    {
    //下面就是一个代码块{}包围
                 {//类中把value值赋成另一个
                        AutoReset auto_reset(&value, count);
                        value *= 2;
                        count++;
                        cout << value << " ";
                 }//类作用的有效区域,出了之后需要把value值还原
     cout << value << endl;
    }
    
    int save,*s;
    AutoReset::AutoReset(int *scoped_variable, int new_value){
      s=scoped_variable;//传入的是指针,把原来指向那个值的指针存下来
      save=*scoped_variable;
      *scoped_variable=new_value;
    }
    // your code will be here
    
    AutoReset::~AutoReset(){
      *s=save;//把存下了的指针还回去
    }      

参考模板

可能用到的函数库

这一篇的最下面总结了模板头文件..

sicily上可以用#include<bits/stdc++.h>来囊括所有函数库

另外附加了三个cplusplus的网页集合

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值