www.9778.com 2

www.9778.com:学堂在线00740043X_2015_T2 C++语言程序设计基础

default 关键字有两类用法

默认值表达式生成类型的默认值。 默认值表达式在泛型类和泛型方法中非常有用。 使用泛型类和泛型方法时出现的一个问题是,如何在无法提前知道以下内容的情况下将默认值赋值给参数化类型 T

从 C# 7.1 开始,当编译器可以推断表达式的类型时,文本 default
可用于默认值表达式。 文本 default 生成与等效项 default(T)(其中,T
是推断的类型)相同的值。
这可减少多次声明类型的冗余,从而使代码更加简洁。 文本 default
可用于以下任一位置:

负数补码 = 反码 + 1
正数补码 = 原码

  1. switch语句中指定默认标签
  2. 默认值表达式
  • T 是引用类型还是值类型。
  • 如果 T 是值类型,它是数值还是用户定义的结构。
  • 变量初始值设定项
  • 变量赋值
  • 声明可选参数的默认值
  • 为方法调用参数提供值
  • 返回语句(或 expression bodied 成员中的表达式)

基本数据类型:
(整数;实数;字符;布尔)类型
(signed/unsigned) signed char
<= (unsigned) short int
<= (unsigned) int
<= (unsigned) long int
www.9778.com:学堂在线00740043X_2015_T2 C++语言程序设计基础。<= long long int

switch 语句

      int caseSwitch = 1;

      switch (caseSwitch)
      {
          case 1:
              Console.WriteLine("Case 1");
              break;
          case 2:
              Console.WriteLine("Case 2");
              break;
          default:
              Console.WriteLine("Default case");
              break;
      }

已知参数化类型 T 的变量 t,仅当 T 为引用类型时,语句 t = null 才有效。 赋值 t = 0 仅对数值类型有效,对结构无效。 解决方案是使用默认值表达式,该表达式对引用类型(类类型和接口类型)返回 null,对数值类型返回零。 对于用户定义的结构,返回初始化为零位模式的结构,该结构根据成员是值还是引用类型,为每个成员生成
0 或 null。 对于可为 NULL
的值类型,default 返回像任何结构一样初始化的System.Nullable<T>。

以下示例展示了文本 default 在默认值表达式中的多种用法:

整数常量:

默认值表达式

default对应各种类型生成默认值列表如下:
|类型|默认值|
|-|-|
|任何引用类型|null|
|数值类型|零|
|bool|false|
|enum|表达式 (E)0 生成的值,其中 E 是枚举标识符。|
|struct|通过如下设置生成的值:将所有值类型的字段设置为其默认值,将所有引用类型的字段设置为null。|
|可以为 null 的类型|HasValue 属性为 false 且 Value 属性未定义的实例。|

罗列一下上述列表中的常见类型对应的值

在C# 7.1 之前

default(string) // null
default(int) // 0
default(int?) // null
default(dynamic) // null
default(DateTime) // 0001/01/01 0:00:00
default(DateTime?) // null

default(T) 表达式不限于泛型类和泛型方法。 默认值表达式可用于任何托管类型

public class Point
{
    public double X { get; }
    public double Y { get; }

    public Point(double x, double y)
    {
        X = x;
        Y = y;
    }
}

public class LabeledPoint
{
    public double X { get; private set; }
    public double Y { get; private set; }
    public string Label { get; set; }

    // Providing the value for a default argument:
    public LabeledPoint(double x, double y, string label = default)
    {
        X = x;
        Y = y;
        this.Label = label;
    }

    public static LabeledPoint MovePoint(LabeledPoint source, 
        double xDistance, double yDistance)
    {
        // return a default value:
        if (source == null)
            return default;

        return new LabeledPoint(source.X + xDistance, source.Y + yDistance, 
        source.Label);
    }

    public static LabeledPoint FindClosestLocation(IEnumerable<LabeledPoint> sequence, 
        Point location)
    {
        // initialize variable:
        LabeledPoint rVal = default;
        double distance = double.MaxValue;

        foreach (var pt in sequence)
        {
            var thisDistance = Math.Sqrt((pt.X - location.X) * (pt.X - location.X) +
                (pt.Y - location.Y) * (pt.Y - location.Y));
            if (thisDistance < distance)
            {
                distance = thisDistance;
                rVal = pt;
            }
        }

        return rVal;
    }

    public static LabeledPoint ClosestToOrigin(IEnumerable<LabeledPoint> sequence)
        // Pass default value of an argument.
        => FindClosestLocation(sequence, default);
}
  • 十进制
  • 八进制
  • 十六进制
    后缀:L / LL / U
    浮点常量默认为double型,如果后缀F(或f)可以使其成为float

默认文本和类型推理

C# 7.1 default的使用常见举例
Visual Studio 2017 默认C#语言版本是7.0,需要自己设置7.1
Alt+Enter快捷键打开项目属性,或者右键点击项目,选择属性,之后选择生成,点击高级,如下图
www.9778.com 1

打开高级生成设置,选择语言版本,选C# 7.1 及以上的版本,如下图
www.9778.com 2

如果没有C# 7.1 及以上的版本可选,请下载.NET Framework
4.7.2,现在最新版本的是4.7.2,直接下载最新版本的,省事。然后重启VS,就能看到7.1及以上的可选项。

以上内容来自MSDN。

 

初始化:

变量初始值设定项

7.1之前:

            var dstring = default(string);
            var dint = default(int);
            var dintNull = default(int?);
            var d = default(dynamic);
            var dt = default(DateTime);
            var dt1 = default(DateTime?);

7.1:

            string s = default;
            int i = default;
            DateTime? dt = default;
            dynamic d = default;

示例代码:

int a = 0
int a(0)
int a = {0}
int a{0}

变量赋值

7.1之前:

            var s = "字符串";
            s = default(string);            

7.1:

           var s = "字符串";
            s = default;

 

其中使用大括号的初始化方式称为列表初始化,列表初始化时不允许信息的丢失。例如使用double值初始化int变量,就会造成数据的丢失。

声明可选参数的默认值

7.1之前:

        void Test(int a, string b = null)
        {

        }           

7.1:

        void Test(int a, string b = default)
        {

        }

int iValue = default(int);
float fValue = default(float);
decimal dValue = default(decimal);
Console.Write(“值类型测试:”);
Console.WriteLine(“{0},{1},{2}”, iValue, fValue, dValue);

逗号运算符:
表达式1,表达式2
求解顺序及结果:
先求解表达式1,再求解表达式2
最终结果为表达式2的值
例:
a = 3 * 5, a * 4最终结果为60

为方法调用参数提供值

7.1之前:

        static void Test(int a, string b)
        {

        } 
        static void Main(string[] args)
        { 
            Test(0, null);
        } 

7.1:

        static void Test(int a, string b)
        {

        }
        static void Main(string[] args)
        { 
            Test(default, default);
        } 

string strValue = default(string);
DateTime? dt = default(DateTime?);
User user = default(User);
Console.Write(“引用类型测试:”);
Console.WriteLine(“{0},{1},{2}”, (null == strValue), (null == user),
(null == dt));
Console.WriteLine();

条件运算:
表达式1?表达式2:表达式3
条件表达式的最终类型为2和3中较高的类型

返回语句

7.1之前:

        static string Test()
        {
            return null;
        }

7.1:

        static string Test()
        {
            return default;
        }

 

sizeof运算符:
sizeof(类型名) 或 sizeof 表达式

expression bodied 成员中的表达式

7.1之前:

public string A => null;

7.1:

public string A => default;

参考:默认值表达式(C#
编程指南)

运行结果:
www.9778.com 3

位运算符:

  • 按位与(&):只有当对应位都为1,则新值中相应位为1,否则为0
  • 按位或(|):如果对应位至少有一个为1,则新值中相应位为1,否则为0
  • 按位异或(^):
    若对应位相同,则结果该位为0;若对应位不同,则结果该位为1
  • 按位取反(~):单目运算符,对一个二进制位按位取反

位运算:

  • 左移运算(<<)
    左移后,低位补0,高位舍弃
  • 右移运算(>>)
    右移后:
    低位:舍弃
    高位

    • 无符号数:补0
    • 有符号数:补“符号位”

隐含转换就时把低类型数据转换为高类型数据

显式转换:
类型说明符(表达式)
(类型说明符)表达式
类型转换操作符<类型说明符>(表达式)
类型转换操作符:const_cast、dynamic_cast、reinterpret_cast、static_cast
例:int(z),(int)z,static_cast<int>(z)三种完全等价

其他控制语句

  • break语句:
    使程序从循环体和switch语句内跳出,继续执行逻辑上的吓一条语句。不宜用在别处。
  • continue语句:
    结束本次循环,接着判断是否执行下一次循环
  • goto语句:
    使程序的执行流程跳转到居于标号所指定的语句。不提倡使用。

类型别名:为已有类型另外命名

  • typedef 已有类型名 新类型名表

typedef double Area,Volume;
typedef int Natural;
Natural i1,i2;
Area a;
Volume v;
  • using 新类型名 = 已有类型名

using Area = double
using Volume = double

不限定作用域枚举类型说明:

  • 枚举元素使常量,不能对它们赋值
    enum Weekday {SUN, MON, TUE, WED, THU, FRI, SAT}
    不能写赋值表达式:SUN = 0
  • 枚举元素具有默认值,它们依次为:0,1,2,……
  • 也可以在声明时另行指定枚举元素的值
    如:enum Weekday{SUN=7,MON=1,TUE,WED,THYU,FRI,SAT}
  • 枚举值可以进行关系运算
  • 整数值不能直接赋给枚举变量
    如需要将整数赋值给枚举变量,应进行强制类型转换
  • 枚举值可以赋给整型变量

auto类型与decltype类型

  • auto:编译器通过初始值自动推断变量的类型
    例如:auto val = val1 + val2
  • decltype:定义一个变量与某一表达式类型相同,但并不用该表达式初始化变量
    例如:decltype(i)j = 2
    表示j以2作为初始值,类型与i一致

struct结构的作用是把一组相互关联的数据整合在一起

函数定义的语法形式:
类型标识符 函数名(形式参数表)
{
语句序列
}
函数原型:类型标识符 被调用函数名(含类型说明的形参表)
递归调用:函数直接或间接调用自身
回文:各位数字左右对称的整数

rand函数:
函数原型:int rand(void);
所需头文件:<cstdlib>
功能和返回值:求出并返回一个伪随机数

srand函数:
原型:void srand(unsigned int seed)
参数:seed产生随机数的种子
所需头文件:<cstdlib>
功能:为使rand()产生一序列伪随机数而设置起始点。使用1作为seed参数可以重新初化rand()

用递归法计算从n个人中选k个人组成一个委员会的不同组合数
分析

  • 由n个人里选k个人的组合数=由n-1个人里选k个人的组合数+由n-1个人里选k-1个人的组合数
  • 当n=k或k=0时组合数为1

将n个盘子从A针移到C针可以分解为三个步骤:

  • 将A上的n-1个盘子移到B针上(借助C针);
  • 把A针上剩下的一个盘子移到C针上;
  • 把n-1个盘走从B针移到C针上(借助A针)

函数的参数传递:

  • 在函数被调用时才分配形参的存储单元
  • 实参可以是常量、变量或表达式
  • 实参类型必须与形参相符
  • 值传递是传递参数值,即单向传递
  • 引用传递可以实现双向传递
  • 常引用作参数可以保障实参数据的安全

引用类型:

  • 引用(&)是标识符的别名
  • 定义一个引用时,必须同时对它进行初始化,使它指向一个已存在的对象
  • 例如:

int i,j;
int &ri = i;//定义int引用ri,并初始化为变量i的引用
j = 10;
ri = j;//相当于i = j
  • 一旦一个引用被初始化后,就不能改为指向其它对象
  • 引用可以作为形参

内联函数:
通常的做法是省略原型,将整个定义(即函数头和所有函数代码)放在本应提供原型的地方

  • 编译时在调用处用函数体进行替换
  • 节省了参数传递
  • 控制转移等开销
    注意:
  • 内联函数体内不能有循环语句和switch语句;
  • 内联函数的定义必须出现在内联函数第一次被调用之前;
  • 对内联函数不能进行异常接口声明。

默认参数值:

  • 可以预先设置默认的参数值,调用时如给出实参,则采用实参值,否则采用预先设置的默认参数值。
  • 例:

int add(int x = 5,int y = 6) {
     return x + y;
}
int main() {
     add(10,20);  //10+20
     add(10);     //10+6
     add();       //5+6
}

默认参数值的说明次序:

  • 有默认参数的形参必须列在形参列表的最右,即默认参数值的右面不能有无默认值的参数;
  • 调用时实参与形参的结合次序是从左向右。
  • 例:

int add(int x,int y = 5,int z = 6);//正确
int add(int x = 1,int y = 5,int z);//错误
int add(int x = 1,int y,int z = 6);//错误

默认参数值与函数的调用位置:

  • 如果一个函数有原型声明,且原型声明在定义之前,则默认参数值应在函数原型声明中给出;如果只有函数的定义,或函数定义之前,则默认参数值可以函数定义中给出。
  • 例:

int add(int x = 5,int y = 6);
//原型声明在前
int main(){
  add();
}
int add(int x,int y){
//此处不能再指定默认值
  return x + y;
}

int add(int x = 5, int y = 6){
//只有定义,没有原型声明
  return x + y;
}
int main(){
  add();
}

函数重载的概念:

  • C++允许功能相近的函数在相同的作用域内以相同函数名声明,从而形成重载。方便使用,便于记忆。

注意事项:

  • 重载函数的形参必须不同:个数不同或类型不同。
  • 编译程序将根据实参和形参的类型及个数的最佳匹配来选择调用哪一个函数。
  • 不要将不同功能的函数声明为重载函数,以免出现调用结果的误解 、混淆

角度值转化为弧度 :
弧度 = 角度值*PI / 180

类与对象

  • 对象: 现实中对象的模拟,具有属性和行为
  • 同一类对象的共同属性和行为。
  • 定义对象时,通过构造函数初始化
  • 删除对象时,通过析构函数释放资源

面向对象程序设计的基本特点:抽象、封装、继承、多态
类定义的语法形式

class 类名称
{
  public:
            公有成员(外部接口)
  private:
             私有成员
  protected:
              保护型成员
};

构造函数的作用

  • 在对象好被创建时使用特定的值构造对象,将对象初始化为一个特定的初始状态

构造函数的调用时机

  • 在对象创建时被自动调用

类内初始值
private:
int hour = 0,minute = 0,second = 0;

私有类型成员

  • 如果紧跟在类名称的后面声明私有成员,则关键字private可以省略

类的成员函数

  • 在类中声明函数原型;
  • 可以在类外给出函数体实现,并在函数名前使用类名加以限定;
  • 也可以直接在类中给出函数体,形成内联成员函数;
  • 允许声明重载函数和带默认参数值的函数

内联成员函数

  • 内联函数体中不要有复杂结构
    (如循环语句和switch语句)。
  • 在类中声明内联成员函数的方式:
  • 将函数体放在类的声明中
  • 在类外实现函数的时候使用inline关键字

默认构造函数

  • 调用时可以不需要实参的构造函数
  • 参数表为空的构造函数
  • 全部参数都有默认值的构造函数
    下面两个都是默认构造函数,如在类中同时出现,将产生编译错误:

Clock();
Clock(int newH=0,int newM=0,int newS=0);

隐含生成的构造函数
如果程序中未定义构造函数,编译器将自动生成一个默认构造函数

  • 参数列表为空,不为数据成员设置初始值;
  • 如果类内定义了成员的初始值,则使用内类定义的初始值;
  • 如果没有定义类内的初始值,则以默认方式初始化;
  • 基本类型的数据默认初始化的值是不确定的。

“=defalut”

  • 如果程序中已定义构造函数,默认情况下编译器就不再隐含生成默认构造函数。如果此时依然希望编译器隐含生成默认构造函数,可以使用“=default”。
  • 例:

class Clock{
public:
Clock() = default;//指示编译器提供默认构造函数
Clock(int newH, int newM, int newS); //构造函数
private:
int hour,minute,second;
}

数组:数组是一种数据形式,能够存储多个同类型的值。
数组的初始化规则:只有定义数组时才能使用初始化,此后就不能使用了,也不能将一个数组付给另一个数组:

int cards[4] = {3, 6, 8, 10}; //okay
int hand[4]; //okay
hand[4] = {5, 6, 7, 9}; //not allowed
hand = cards; //not allowed

然而,可以用下标分别给数组中的元素赋值。

常量表达式是指值不会改变并且在编译过程就能得到计算结果的表达式。显然,字面值属于常量表达式,用常量表达式初始化的const对象也是常量表达式。
一个对象(或表达式)是不是常量表达式由它的数据类型和初始值共同决定
C++11新标准规定,允许将变量声明为constexpr类型以便由编译器来验证变量的值是否是一个常量表达式。声明为constexpr的变量一定是一个常量,而且必须用常量表达式初始化