02. C++概览:基础知识

初始化器列表(通用)

  • 确保不会发生导致信息丢失的转换(窄化类型转换)
  • int i1 = 7.2 // 变成7,信息丢失,意料之外?
    int i2 {7.2} // 报错,conversion from 'double' to 'int', possible loss of data
    int i2 = {7.2} // 报错,并且 = 多余
    

引入新名字时最好已经有了一个合适的值

  • 常量声明时必须初始化
  • 普通变量尽可能在声明时初始化

C++ 支持两种不变性概念

  • const:运行时和编译值都可,承诺不改变这个值

    • 用于说明接口,传入函数不用担心被改变
  • constexpr:编译时求值(如果在编译时无法求值,会报错)

    • 作用:作用是允许将数据置于只读内存中(不太可能被破坏)以及提升性能
    • const int dmv = 17;
      int var = 17;
      constexpr double max = 1.4 * dmv; // 可以,dmv 是常量
      constexpr double max1 = 1.4 * var; // 不可以,var 是变量
      
    • 如果函数在常量表达式中使用,则必须定义成 constexpr​,并且函数必须非常简单(即只能由一条用于计算某个值的 return 语句)
    • constexpr​ 函数可以接收非常量实参,但结果不再是常量表达式
    • constexpr double square(double x) {return x*x;}
      

范围 for

#include <iostream>

int main() {
	using namespace std;

	int v[] = { 0,1,2,3,4,5,6,7,8,9 };

	// 引用值
	for (auto& x : v)
		x *= 10;

	// 拷贝值
	for (auto x : v)
		cout << x << '\n';

	for (auto x : { 10, 21, 32, 43, 54, 65 })
		cout << x << '\n';

}

类型

内置类型可由以下构造

  • 声明运算符 &*[]
  • 基本类型
  • const 修饰符

与之对应的是用户自定义类型,如类和枚举等

用户自定义类型

  • 结构体 struct

    • 访问成员的两种方式

      • 通过名字或引用:使用 .​ 访问
      • 通过指针:使用 ->​ 访问
    • 数据和操作分割(即数据 + 函数,函数接收数据作为参数)

  • class

    • 数据和操作紧密联系
    • 成员可见性可控
  • 枚举 enum

    • 普通 enum​,可隐式赋值给整型,但不可隐式被整型赋值
    • enum class​,不可隐式赋值给整型,不可隐式被整型赋值
    • #include <iostream>
      
      int main() {
      	// 枚举值直接暴露出来
      	enum Color {
              RED, GREEN, BLUE
      	};
      	// 枚举值在 ColorClass 作用域中
      	enum class ColorClass {
      		YELLOW, ORANGE, PURPLE
      	};
      
      	Color color = GREEN;
      	int c1 = GREEN;// OK
      	//Color c2 = 1;// 不OK
      
          ColorClass colorClass = ColorClass::ORANGE;
      	//ColorClass colorClass = ORANGE; // 不OK
          //int c3 = ColorClass::ORANGE; // 不OK
      	//ColorClass c4 = 1; // 不OK
      
      	std::cout << "Color: " << color << std::endl;
          std::cout << "c1: " << c1 << std::endl;
          std::cout << "ColorClass: " << static_cast<int>(colorClass) << std::endl;
      }
      

模块化

将接口和实现分离开

  • 声明
  • 定义

分离编译

声明和定义放置在分离的源文件里,并被分别编译

优点:编译时间缩短

class Vector {
public:
    Vector(int s);
    double& operator[](int i);
    int size();

private:
    double* elem; // elem指向一个数组,该数组包含sz个double
    int sz;
};
#include "Vector.h" // 获得接口

Vector::Vector(int s) : elem(new double[s]), sz(s) {
    // 构造函数的实现
}

double& Vector::operator[](int i) {
    return elem[i]; // 下标操作符重载函数的实现
}

int Vector::size() {
    return sz; // size函数的实现
}

image

名字空间 namespace

一方面表达某些声明是属于一个整体的,另一方面表明它们的名字不会与其他名字空间中的名字冲突。

namespace My_code {
    class complex {/*...*/ };
    complex sqrt(complex);

    // ...

    int main();
}

int My_code::main() {
    complex z{ 1, 2 };
    auto z2 = sqrt(z);
    std::cout << '{' << z2.real() << ',' << z2.imag() << "}\n";
    // .
};
// 真正的 main() 定义在全局名字空间中
int main() {
    return My_code::main();
}

错误处理

异常

#include <iostream>
#include <stdexcept>

class Vector {
public:
    // 构造函数
    Vector(int s) : sz(s) {
        elem = new double[sz];
    }

    // 析构函数
    ~Vector() {
        delete[] elem;
    }

    // 重载下标运算符
    double& operator[](int i) {
        if (i < 0 || i >= sz) {
            throw std::out_of_range("Index out of range");
        }
        return elem[i];
    }

    // 获取向量大小
    int size() {
        return sz;
    }

private:
    double* elem; // 指向double数组的指针
    int sz;       // 向量大小
};

int main() {
    Vector v(5); // 创建一个大小为5的Vector

    try {
        v[10] = 3.14; // 尝试访问越界的元素
    }
    catch (const std::out_of_range& e) {
        std::cerr << "Caught an exception: " << e.what() << std::endl;
    }

    return 0;
}

不变式

前置条件(即:索引值必须在[0:size())范围内)未满足,函数拒绝执行,并抛出异常

对于类来说,这样一条假定某事为真的声明称为类的不变式(class invariant) ,简称为不变式(invariant)

在这个例子中不变式是:elem 指向一个含有 sz 个 double 的数组

建立类的不变式是构造函数的任务(从而成员函数可以依赖于该不变式),它的另一个作用是确保当成员函数退出时不变式仍然成立。

Vector v(-27) // 会报错

修正后:

Vector(int s) : sz(s) {
	if (s<0) throw std::length_error{};
	elem = new double[sz];
}

静态断言

编译时处理,适用于任何可以表达为常量表达式的东西

int main() {
	// OK
    static_assert(4<=sizeof(int), "int is not an integral type."); 

	// 编译报错:error C2338: static_assert failed: 'int is not an integral type.'
    static_assert(4>sizeof(int), "int is not an integral type."); 
}

暂无评论

发送评论 编辑评论


				
|´・ω・)ノ
ヾ(≧∇≦*)ゝ
(☆ω☆)
(╯‵□′)╯︵┴─┴
 ̄﹃ ̄
(/ω\)
∠( ᐛ 」∠)_
(๑•̀ㅁ•́ฅ)
→_→
୧(๑•̀⌄•́๑)૭
٩(ˊᗜˋ*)و
(ノ°ο°)ノ
(´இ皿இ`)
⌇●﹏●⌇
(ฅ´ω`ฅ)
(╯°A°)╯︵○○○
φ( ̄∇ ̄o)
ヾ(´・ ・`。)ノ"
( ง ᵒ̌皿ᵒ̌)ง⁼³₌₃
(ó﹏ò。)
Σ(っ °Д °;)っ
( ,,´・ω・)ノ"(´っω・`。)
╮(╯▽╰)╭
o(*////▽////*)q
>﹏<
( ๑´•ω•) "(ㆆᴗㆆ)
😂
😀
😅
😊
🙂
🙃
😌
😍
😘
😜
😝
😏
😒
🙄
😳
😡
😔
😫
😱
😭
💩
👻
🙌
🖕
👍
👫
👬
👭
🌚
🌝
🙈
💊
😶
🙏
🍦
🍉
😣
Source: github.com/k4yt3x/flowerhd
颜文字
Emoji
小恐龙
花!
上一篇
下一篇