C++11 auto,异常处理,非虚接口

3. C++11 的 auto

  • 是一个占位符
  • 根据 = 右侧的表达式类型自动推导变量类型
  • 所以 auto 变量必须初始化

注意:

  • 适合: 可以用在迭代器的场景, 可以用在范围 for 循环中;
  • 默认情况下, auto 推导出的类型是值类型, 会丢弃引用const限定符
  • 即使这样, 也不会忽略底层的const(这有些费解, 表层的const和底层的const需要区分开), 比如 const int *p, auto 推导出来是 const int *, 我们仍然不能通过这个指针修改指针指向的值
int main() {
    std::vector<int> vec = {1, 2, 3, 4, 5};
    for (auto v:vec) {
        v = v * 2; // 无效修改
    }

    for (auto &v:vec) {
        v = v * 2; // 有效修改
    }

    std::vector<const int*> cvec = {new int(1), new int(2)};
    for (auto p:cvec) {
        *p = 10; // 错误, 不能修改 const int
    }
}

4. 异常处理

  • 错误:
    • 语法错误: 编译器检测
    • 逻辑错误: 测试
  • 异常 Exeption
    • 运行环境造成, 比如内存不足, 文件不存在…
    • 需要异常处理
    • 特征: 可以预见, 无法避免
    • 作用: 提高程序的鲁棒性, 分离错误处理代码和正常代码, 提高代码可读性和可维护性

C++ 异常处理机制:(一种专门, 清晰描述异常处理过程的机制)

  • try, 监控, try{<语句序列>}

  • throw, 抛出异常对象, throw <表达式>;

  • catch, 捕获异常, catch(<类型> <参数名>){<语句序列>}

  • 如果要throw, 可能是一个临时对象, 这时候要调用拷贝构造函数, (ps: 不要throw 一个指针)

  • catch 捕获异常只需要按照引用类型捕获;

  • 一个 try 语句之后可以多个 catch 语句块, 用于捕获不同类型的异常;

  • 如果抛出的异常没有被捕获, 那么由系统的 abort 处理

注意 catch 块的顺序
  • 如果先基类, 后子类, 那么子类的 catch 块永远不会被执行到;
  • 而且, 这时候会出现对象切片问题, 抛出的是子类对象, 但是捕获的是基类对象, 只能捕获到基类的部分
无参数的throw
  • throw; 重新抛出当前捕获的异常
    • catch(...) { ... throw; }

5. IO 处理 (虚化全局函数)

  • 操作符 << 和 >> 重载
  • 全局函数没有多态性, CPoint2D, CPoint3D, <<>>只能作为全局函数重载, 我们首先写出一种存在问题的方案:
class Cpoint2D {
    double x, y;
public:
    Cpoint2D(double x=0, double y=0): x(x), y(y) {}
    friend std::ostream& operator<<(std::ostream &out, const Cpoint2D &p);
};

std::ostream& operator<<(std::ostream &out, const Cpoint2D &p) {
    out << "(" << p.x << ", " << p.y << ")";
    return out;
}

class Cpoint3D : public Cpoint2D {
    double z;
public:
    Cpoint3D(double x=0, double y=0, double z=0): Cpoint2D(x, y), z(z) {}
    friend std::ostream& operator<<(std::ostream &out, const Cpoint3D &p);
};

std::ostream& operator<<(std::ostream &out, const Cpoint3D &p) {
    out << "(" << p.x << ", " << p.y << ", " << p.z << ")";
    return out;
}

这个时候的问题在于, 如果我们有一个 Cpoint2D* p = new Cpoint3D(1,2,3); cout << *p;, 这个时候调用的还是 Cpoint2Doperator<<, 因为全局函数没有多态性;

  • 解决方案: 这时只能虚化非成员函数, non-virtual interface, NVI
    class Cpoint2D {
        double x, y;
      public:
          Cpoint2D(double x=0, double y=0): x(x), y(y) {}
          virtual void display(ostream &out) {
              out << "(" << x << ", " << y << ")";
          }
    };
      std::ostream& operator<<(std::ostream &out, const Cpoint2D &p) {
          p.display(out);
          return out;
      }
      class Cpoint3D : public Cpoint2D {
          double z;
      public:
          Cpoint3D(double x=0, double y=0, double z=0): Cpoint2D(x, y), z(z) {}
          void display(ostream &out) override {
              out << "(" << x << ", " << y << ", " << z << ")";
          }
      };
      ostream& operator<<(ostream &out, const Cpoint3D &p) {
          p.display(out);
          return out;
      }
    
  • 这样就可以实现多态性
虚的构造函数, 包含例子

我们由 NewsLetter 报纸类, NLComponent 抽象类, TextBlock 文字类和 Graphic图像类都继承 NLComponent

class NLComponent{...};
class TextBlock : public NLComponent {...};
class Graphic : public NLComponent {...};
class NewsLetter {
public:
    NewsLetter(istream &in);
    NewsLetter(const NewsLetter &rhs);
private:
    list<NLComponent*> components;
};

// 关键问题就在这里, 如何实现拷贝构造函数
NewsLetter::NewsLetter(const NewsLetter &rhs) {
    for (NLComponent* comp : rhs.components) {
        components.push_back(???); // 如何多态性的构造对象, new TextBlock? new Graphic?
    }
}

解决方案, 在 NLComponent 中定义一个虚的克隆函数 clone, 由子类实现具体的克隆逻辑

virtual NLComponent* clone() const = 0; // 纯虚函数
virtual TextBlock* clone() const override {
    return new TextBlock(*this); // 调用拷贝构造函数
}
virtual Graphic* clone() const override {
    return new Graphic(*this); // 调用拷贝构造函数
}
// 在 NewsLetter 的拷贝构造函数中调用 clone
NewsLetter::NewsLetter(const NewsLetter &rhs) {
    for (NLComponent* comp : rhs.components) {
        components.push_back(comp->clone()); // 多态性地克隆对象
    }
}
BST array 和 balancedBST array, 多态编程不能直接使用对象数组
class BST{...};
class balancedBST : public BST{...};

void printBSTArray(ostream &s, const BST array[], int size) {
    for (int i=0; i<size; i++) {
        s << array[i]; // 调用 operator<<
    }
}

BalancedBST bbstArray[10];
printBSTArray(cout, bbstArray, 10); // 错误, 切片对象
  • 如果使用指针数组, 那么可以就实现多态
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值