精华内容
下载资源
问答
  • 2. 命名空间 3. C++输入&输出 4. 缺省参数 5. 函数重载 6. 引用 7. 内联函数 宏:定义常量、定义宏函数。(缺陷很大)#define 8. auto关键字(C++11) 9. 基于范围for循环(C++11) 1.什么是C++ ...

    目录

     

    1.什么是C++

    c++关键字:(c++98)

    2. 命名空间

    3. C++输入&输出 

    4. 缺省参数

    5. 函数重载

    6. 引用

    7. 内联函数

    宏:定义常量、定义宏函数。(缺陷很大)#define

    8. auto关键字(C++11)

    9. 基于范围的for循环(C++11)

     

     


    1.什么是C++

              C语言是结构化和模块化的语言,适合处理较小规模的程序。对于复杂的问题,规模较大的程序,需要高度的抽象和建模时,C语言则不合适。为了解决软件危机, 20世纪80年代, 计算机界提出了OOP(objectoriented programming:面向对象)思想,支持面向对象的程序设计语言应运而生。

           C++是基于C语言而产生的,它既可以进行C语言的过程化程序设计,又可以进行以抽象数据类型为特点的基于对象的程序设计,还可以进行面向对象的程序设计

    c++关键字:(c++98)

     

    asm

    do

    if

    return

    try

    continue

    auto

    double

    inline

    short

    typedef

    for

    bool

    dynamic_cast

    int

    signed

    typeid

    public

    break

    else

    long

    sizeof

    typename

    throw

    case

    enum

    mutable

    static

     

    union

    wchar_t

    catch

    explicit

    namespace

    static_cast

     

    unsigned

    default

    char

    export

    new

    struct

    using

    friend

    class

    extern

    operator

    switch

    virtual

    register

    const

    false

    private

    template

    void

    true

    const_cast

    float

    protected

    this

    volatile

    while

    delete

    goto

    reinterpret_cast

     

     

     

    2. 命名空间

                        在C/C++中,变量、函数和后面要学到的类都是大量存在的,这些变量、函数和类的名称将都存在于全局作用

    域中,可能会导致很多冲突。使用命名空间的目的是对标识符的名称进行本地化,以避免命名冲突或名字污染。

    2.1 命名空间定义

            定义命名空间,需要使用到namespace关键字,后面跟命名空间的名字,然后接一对{}即可,{}中即为命名空 间的成员。

    //1. 普通的命名空间
    namespace N1  // N1为命名空间的名称
    {
    // 命名空间中的内容,既可以定义变量,也可以定义函数
    int a;
    int Add(int left, int right) {
        return left + right; }}
    //2. 命名空间可以嵌套
    namespace N2
    {
    int a;
    int b;
    int Add(int left, int right) {
        return left + right; }
    namespace N3
    {
        int c;
        int d;
        int Sub(int left, int right)
       {
            return left - right;
       }
    }}
    //3. 同一个工程中允许存在多个相同名称的命名空间
    //   编译器最后会合成同一个命名空间中。
    namespace N1
    {
    int Mul(int left, int right) {
        return left * right; }}

    注意:一个命名空间就定义了一个新的作用域,命名空间中的所有内容都局限于该命名空间中

    2.2 命名空间使用

    命名空间的使用有三种方式:

     

    3. C++输入&输出 

     

    • 加命名空间名称及作用域限定符————————————————空间名 :: 变量名
    • 使用using将命名空间中成员引入———————————————using 空间名 :: 变量名
    • 使用using namespace 命名空间名称引入————————————using namespace 空间名

    1. 使用cout标准输出(控制台)cin标准输入(键盘)时,必须包含< iostream >头文件以及std标准命名空间。

    2. 使用C++输入输出更方便,不需增加数据格式控制,比如:整形--%d,字符--%c。

     

    4. 缺省参数

    4.1 缺省参数概念

    缺省参数是声明或定义函数时为函数的参数指定一个默认值。在调用该函数时,如果没有指定实参则采用该默认值,否则使用指定的实参。

    4.2 缺省参数分类

    1.全缺省参数

    2.半缺省参数

    注意:

    1. 半缺省参数必须从右往左依次来给出,不能间隔着给

    2. 缺省参数不能在函数声明和定义中同时出现(一般在声明位置给比较好,)

    3. 缺省值必须是常量或者全局变量

    4. C语言不支持(编译器不支持)

    5. 函数重载

    5.1 函数重载概念

    函数重载:是函数的一种特殊情况,C++允许在同一作用域中声明几个功能类似的同名函数,这些同名函数的形参列表(参数个数 或 类型 或 顺序)必须不同,常用来处理实现功能类似数据类型不同的问题。返回值类型无关。

    5.2 extern “C”

    有时候在C++工程中可能需要将某些函数按照C的风格来编译,在函数前加extern "C",意思是告诉编译器,将该函数按照C语言规则来编译。

    5.3传值和传地址比较

    传值:优点:安全,不会影响实参

               缺点:效率低,不能通过改变形参来改变实参。

    传地址:优点:效率高,可改变形参来改实参。

                  缺点:会影响实参,可读性差。

    6. 引用

    6.1 引用概念

    引用不是新定义一个变量,而是给已存在变量取了一个别名,编译器不会为引用变量开辟内存空间,它和它引用的变量共用同一块内存空间。

    类型& 引用变量名(对象名) = 引用实体;

    注意:引用类型必须和引用实体同种类型的。

    6.2 引用特性

    1. 引用在定义时必须初始化

    2. 一个变量可以有多个引用

    3. 引用一旦引用一个实体,再不能引用其他实体

    6.3 常引用

    
    #include<iostream>
    
     
    
    using namespace std;
    
     
    
    int main()
    
     
    
    {
    
     
    
                int a = 10;
    
     
    
                //普通引用  必须初始化
    
     
    
                int &b = a;
    
     
    
                //常引用
    
     
    
                int c = 20;
    
     
    
                const int &d = c;//常引用 是让 变量引用 具有只读属性 不能通过d 去修改c
    
     
    
                //常引用初始化有两种情况
    
     
    
                //(1)用变量 初始化常引用
    
     
    
                int e = 30;
    
     
    
                const int &f = e;//用e变量去初始化 常引用
    
     
    
                //(2)用字面量 去初始化 常量引用
    
     
    
                const int g = 40;//c++编译器把a放到符号表中
    
     
    
                //int &m = 41;//普通引用 引用一个字面量  字面量中没有内存地址
    
     
    
                const int &m = 43;//c++编译器会分配内存空间 给&m
    
     
    
                cout <<"m="<<m << endl;  //输出为43
    
     
    
                cout << "f=" <<f<< endl;//输出为30
    
     
    
                system("pause");
    
     
    
    }
    

    6.4 使用场景

    1. 做参数

    2. 做返回值

    注意:如果函数返回时,离开函数作用域后,其栈上空间已经还给系统,因此不能用栈上的空间作为引用类型返回。如果以引用类型返回,返回值的生命周期必须不受函数的限制(即比函数生命周期长)

    6.5 传值、传引用效率比较

    以值作为参数或者返回值类型,在传参和返回期间,函数不会直接传递实参或者将变量本身直接返回,而是传递实参或者返回变量的一份临时的拷贝,因此用值作为参数或者返回值类型,效率是非常低下的,尤其是当参数或者返回值类型非常大时,效率就更低。

     

    6.6 引用和指针的区别

    语法概念上引用就是一个别名,没有独立空间,和其引用实体共用同一块空间。

    底层实现上实际是有空间的,因为引用是按照指针的方式实现的。

    引用和指针的不同点:

    1. 引用在定义时必须初始化,指针没有要求

    2. 引用在初始化时引用一个实体后,就不能再引用其他实体,而指针可以在任何时候指向任何一个同类型实体 

    3. 没有NULL引用,但有NULL指针

    4. sizeof中含义不同引用结果为引用类型的大小,但指针始终是地址空间所占字节个数

    5. 引用自加即引用的实体增加1,指针自加即指针向后偏移一个类型的大小

    6. 有多级指针,但是没有多级引用

    7. 访问实体方式不同,指针需要显式解引用,引用编译器自己处理

    8. 引用比指针使用起来相对更加安全。

    7. 内联函数

    宏:定义常量、定义宏函数。(缺陷很大)#define

    宏的优缺点?

    优点:

    1.增强代码的复用性。

    2.提高性能。

    缺点:

    1.不方便调试宏。(因为预编译阶段进行了替换)

    2.导致代码可读性差,可维护性差,容易误用。

    3.没有类型安全的检查 。

    C++有哪些技术替代宏

    1. 常量定义 换用const

    2. 函数定义 换用内联函数

    特性:替换,在编译期间

    const修饰的变量,具有宏常量特性:替换,在编译期间。

    7.1 概念

    inline修饰的函数叫做内联函数,编译时C++编译器会在调用内联函数的地方展开,没有函数压栈的开销,内联函数提升程序运行的效率。

    查看方式:

    1. release模式下,查看编译器生成的汇编代码中是否存在call Add

    2. debug模式下,需要对编译器进行设置,否则不会展开(因为debug模式下,编译器默认不会对代码进行 优化,以下给出vs2013的设置方式)

     

    7.2 特性

    1. inline是一种以空间换时间的做法,省去调用函数额开销。所以代码很长或者有循环/递归的函数不适宜使用作为内联函数。

    2. inline对于编译器而言只是一个建议,编译器会自动优化,如果定义为inline的函数体内有循环/递归等等,编译器优化时会忽略掉内联。

    3. inline不建议声明和定义分离,分离会导致链接错误。因为inline被展开,就没有函数地址了,链接就会找不到。

    8. auto关键字(C++11)

    cout << typeid(a).name() << end 

    查看a变量类型。

    8.1 auto简介

    在早期C/C++auto的含义是:使用auto修饰的变量,是具有自动存储器的局部变量。

    C++11中,标准委员会赋予了auto全新的含义即:auto不再是一个存储类型指示符,而是作为一个新的类型指示符来指示编译器,auto声明的变量必须由编译器在编译时期推导而得

    【注意】

    使用auto定义变量时必须对其进行初始化,在编译阶段编译器需要根据初始化表达式来推导auto的实际类型。因此auto并非是一种类型的声明,而是一个类型声明时的占位符,编译器在编译期会将auto替换为变量实际的类型

    8.2 auto的使用细则

    1. auto与指针和引用结合起来使用

    auto声明指针类型时,用autoauto*没有任何区别,但用auto声明引用类型时则必须加&

    2. 在同一行定义多个变量

    当在同一行声明多个变量时,这些变量必须是相同的类型,否则编译器将会报错,因为编译器实际只对第一个类型进行推导,然后用推导出来的类型定义其他变量

    8.3 auto不能推导的场景

    1. auto不能作为函数的参数

    2. auto不能直接用来声明数组

    3. 为了避免与C++98中的auto发生混淆,C++11只保留了auto作为类型指示符的用法

    4. auto在实际中最常见的优势用法就是跟以后会讲到的C++11提供的新式for循环,还有lambda表达式等进行配合使用。

    5. auto不能定义类的非静态成员变量

    6. 实例化模板时不能使用auto作为模板参数

    9. 基于范围的for循环(C++11)

    9.1 范围for的语法

    对于一个有范围的集合而言,由程序员来说明循环的范围是多余的,有时候还会容易犯错误。因此C++11中引入了基于范围的for循环。for循环后的括号由冒号”分为两部分:第一部分是范围内用于迭代的变量,第二部分则表示被迭代的范围

    void TestFor()
    {
    int array[] = { 1, 2, 3, 4, 5 };
    for(auto& e : array)// e需要改变,所以加引用
         e *= 2;
    for(auto e : array)
         cout << e << " ";
    return 0; }

    注意:与普通循环类似,可以用continue来结束本次循环,也可以用break来跳出整个循环

    9.2 范围for的使用条件

    1. for循环迭代的范围必须是确定的

    对于数组而言,就是数组中第一个元素和最后一个元素的范围;对于类而言,应该提供beginend的方法,beginend就是for循环迭代的范围。

    2. 迭代的对象要实现++==的操作

    10. 指针空值nullptr(C++11)

    为了避免混淆,C++11提供了nullptr,即:nullptr代表一个指针空值常量。nullptr是有类型的,其类型为nullptr_t

    注意:

    1. 在使用nullptr表示指针空值时,不需要包含头文件,因为nullptrC++11作为新关键字引入的

    2. C++11中,sizeof(nullptr) sizeof((void*)0)所占的字节数相同。

    3. 为了提高代码的健壮性,在后续表示指针空值时建议最好使用nullptr

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

         

     

     

     

     

                     

     

     

               

            

     

     

    展开全文
  • C++入门知识在我们学习了C语言后,我们开始了C++学习,而...为了避免,在大规模程序设计中,以及在程序员使用各种各样C++库时,这些标识符命名发生冲突,标准C++引入了关键字namespace(命名空间/名字空间/名

    C++入门知识

    在我们学习了C语言后,我们开始了C++的学习,而学习C++的第一节课,我们需要知道C++一些不同于C语言的基本特点:
    例如:
    1:命名空间

    在C++中,名称(name)可以是符号常量、变量、宏、函数、结构、枚举、类和对象等等。为了避免,在大规模程序的设计中,以及在程序员使用各种各样的C++库时,这些标识符的命名发生冲突,标准C++引入了关键字namespace(命名空间/名字空间/名称空间/名域),可以更好地控制标识符的作用域。

     C++引入了命名空间namespace主要解决了多个程序员在编写同一个项目中可能出现的函数等重名的现象。解决方法就是加上自己的命名空间。这样就可以很好的控制。
     

    #define _CRT_SECURE_NO_WARNINGS 1 
    
    #include <iostream>
    using namespace std;
    
    namespace A1
    {
        int a = 10;
    }
    namespace A2
    {
        int a = 20;
    }
    
    using namespace  A2;
    int main()
    {
        cout<<a<<endl;
        cout<<A1::a<<endl;
        return 0;
    }

    iostream是输入输出流,using namespace + 命名空间名就可以使用该命名空间。就相当于将该命名空间里的变量展开,也就是释放命名空间里的东西。就如上面程序里的using namespace A2这一句,正因为有了这一句所以下面cout<

    #include <iostream>
    
    using namespace std;
    int main()
    {
        std::cout<<"hello bit!"<<endl;
        return 0;
    }

    正因为所有的标准库函数都在标准命名空间std中进行了定义。所以要想使用cout,就必须使用std命名空间,使用方法有两种;第一种:using namespace std; 第二种 : std**::**cout;

    另外命名空间的定义是:
    有名的命名空间
    namespace 命名空间名
    {
    变量;
    }

    无名的命名空间:
    namespace
    {
    变量;
    }

    命名空间也支持多层嵌套
    例如:

    #include <iostream>
    
    using namespace std;
    
    namespace A1
    {
        int a = 2;
        namespace A2
        {
            int a = 1;
        }
    }
    int main()
    {
        cout<<A1::a<<endl;
        cout<<A1::A2::a<<endl;
        return 0;
    }

    结果输出2和1;
    2:C++基本的输入输出流

    #include <iostream>
    using namespace std;
    
    int main()
    {
        cout<<"hello bit!"<<endl;
        return 0;
    }

    字符串“hello bit!“流向控制台然后输出。
    cout是标准输出流对象,<<是输出操作符。
    cin是标准输入流对象,>>是输入操作符。
    endl是换行操作符。

    3:重载:
    重载定义:同一个作用域,函数名相同,参数不同(既包括参数类型,也包括参数个数)。这样的名字相同而参数不同的函数或者方法,互相之间称之为重载的函数或者方法。
    返回值不同,不能构成重载
    例如下面的代码,编译器会报错。原因就是那两个函数不构成重载,有语法错误。

    #include <iostream>
    
    using namespace std;
    void f(int i)
    {
    
    }
    int f(int i)
    {
        return i;
    }
    
    int main()
    {
        f(2);
        return 0;
    }

    C++为什么支持重载?
    举个例子:

    #include <iostream>
    
    using namespace std;
    void f(int i)
    {
    
    }
    float f(float i)
    {
    
    }
    
    int main()
    {
        return 0;
    }

    上面的函数,在C++中,编译器在编译后再库中的名字为_f_int和_f_float. 而在C语言中,编译器在编译后在库中的名字为_f 而且两个函数的名字都如此。在找名字链接时,在C语言种两个名字一样,就会在链接中报错,C++中名字不一样,所以不会报错,也就是C++支持重载的原因。

    4:C++缺省:
    定义:所谓缺省参数,顾名思义,就是在声明方法的某个参数的时候为之指定一个默认值,在调用该方法的时候如果采用该默认值,你就无须指定该参数。缺省参数使用主要规则:调用时你只能从最后一个参数开始进行省略,换句话说,如果你要省略一个参数,你必须省略它后面所有的参数。缺省参数的使用规则还包括:带缺省值的参数必须放在参数表的最后面。

    例如:

    #include <iostream>
    
    using namespace std;
    void add(int x,int y = 1)
    {
        cout<<x+y<<endl;
    }
    void add1(int x = 10,int y = 20)
    {
        cout<<x+y<<endl;
    }
    int main()
    {
        add(1);
        add1();
        return 0;
    }

    add1()是全缺省,add()是半缺省。

    5:指针与引用:

    引用是一个全新的概念,是C++与C语言的一个区别,在概念上来讲,引用不是定义了一个新的变量,而是给已经存在的变量取了个别名,编译器不会为引用重新开辟一个空间,而是和它的引用对象共用同一块内存空间。但是,如果严格的来说,通过看引用的汇编语言,我们就会发现引用其实就是用指针实现的。

    要使用引用,就必须注意几点:
    1:引用在定义时必须初始化;
    2:一个变量可以有多个引用;
    3:引用一旦使用,就不能改变;
    4:引用的访问范围不能大于被引用对象的范围;

    #include <iostream>
    
    using namespace std;
    void test()
    {
        int num = 5;
        int& a = num;
        cout<<a<<endl;
    }
    int main()
    {
        test();
        return 0;
    }

    输出5;

    a是变量num的别名;
    不能使用常引用来改变变量的值;
    例如:

    void test()
    {
        int num = 5;
        const int& a = num;
        //a = 3;//不允许
        num = 3;
        cout<<a<<endl;
    }

    a是常引用,所以不能通过常引用来改变变量的值。
    长引用必须被常引用所引用;
    例如:

    void test()
    {
        int num = 3;
        const int& a = num;
        int& b = a;//不被允许;
    }
    void test()
    {
        double a = 0.0;
        const int& b = a;//可以
        int& b = a;//不被允许,因为b是int& ,而a是double,两个类型不匹配,在进行命名时会生成一个临时变量,而临时变量具有常属性,所以要用const int&
    }
    int main()
    {
        test();
        return 0;
    }

    上面我们说过,引用是用指针实现的,那么它就具有一些指针的能力。比如它可以做函数的参数;
    引用做参数有两个优点:
    (1):可以在函数内部对外面传参过来的变量别名所对应的变量进行修改。
    (2):提高函数调用和运行效率。

      void swap(int& a,int& b)
    {
        int temp = 0;
        temp = a;
        a = b;
        b = temp;
    }
    int main()
    {
        int num1 = 2;
        int num2 = 3;
        swap(num1,num2);
        return 0;
    }

    引用做返回值
    (1): 以引用返回函数值,定义函数时需要在函数名前加上&。
    (2): 用引用返回函数值是为了不在内存中产生被返回值的副本。

    int& add(int a,int b)
    {
        int c = a+b;
        return c;
    }
    int main()
    {
        int num1 = 2;
        int num2 = 3;
        add(num1,num2);
        return 0;
    }

    这个例子就是引用做返回值。
    最好不要返回局部变量的引用,因为在函数返回后,就不能通过引用找到对象。所以要尽量避免这样的问题。
    但是,如果返回值字节较长,导致寄存器不能存下,这时候可以使用引用来提高效率。前提是你要确保函数返回后,原来函数栈帧里的数据不被修改。

    6:指针与引用的区别:

    相同点:指针和引用的底层实现类型,都是按照指针的方式来实现的。
    不同点:
    (1):引用定义必须初始化,必须对应某个变量的,而且不能更改;而指针可以初始化成NULL;指针也可以改变。
    (2):sizeof(引用)是求被引用类型的大小。
    而sizeof(指针)在32位平台下,始终是4个字节。
    (3):引用++可以使变量++,而指针++,则改变了指针的指向。
    (4):引用比指针相对安全。

    展开全文
  • 1.C++中的关键字(了解) 2.命名空间 2.1 什么是命名空间 ...使用命名空间的目的对标识符的名称进行本地化,以避免命名冲突或名字污染。 命名空间在C++程序中的使用: 2.2 命名空间的定义和

    目录

    1.C++中的关键字(了解)

    2.命名空间

    3.C++的输入和输出

    4.缺省参数和函数重载

    5.引用

    6.内联函数

    面试题(重点)

    7.C++11新内容


    1.C++中的关键字(了解)

    2.命名空间

    2.1 什么是命名空间

    在C++中,变量、函数、类都是大量存在的,这些变量、函数和类的名称都存在与全局作用域中,这样就会产生很多冲突。例如:在软件开发过程中,一个软件产品大多都是由多个开发人员协作完成的,这样就有可能不同的开发人员使用了相同的变量名、函数名以及类名等。为了解决这些问题,C++中引入了命名空间的概念。

    使用命名空间的目的是对标识符的名称进行本地化,以避免命名冲突或名字污染。

    命名空间在C++程序中的使用:

    2.2 命名空间的定义和使用

    2.2.1 定义命名空间

    命名空间的定义需要使用namespace关键字,同时命名空间可以嵌套定义、一个文件中也支持多个同名的命名空间(编译时会自动合成为一个命名空间)。

    1)基本格式

    namespace namespace_name{//命名空间成员}

    2)几种定义格式举例

    //1. 普通的命名空间
    namespace N1 // N1为命名空间的名称
    {
            // 命名空间中的内容,既可以定义变量,也可以定义函数
            int a;
            int Add(int left, int right)
            {
                    return left + right;
            }
    }
     
    //2. 命名空间可以嵌套
    namespace N2
    {
            int a;
            int Add(int left, int right)
            {
                    return left + right;
            }
     
            namespace N3
            {
                    int b;
                    int Sub(int left, int right)
                    {
                            return left - right;
                    }
            }
    }
     
    //3. 同一个工程中允许存在多个相同名称的命名空间,编译器最后会合成同一个命名空间中。
    namespace N1
    {
            int Mul(int left, int right)
            {
                    return left * right;
            }
    }

    注意:一个命名空间就定义了一个新的作用域,命名空间中的所有内容都局限于该命名空间中。

    2.2.2 命名空间的三种使用方法

    1)加命名空间名称及作用域限定符

    int main(){

    cout<<N1::a<<endl; //每次使用都需要加命名空间名作用域限定符

    return 0;}

    2)使用using将命名空间中成员引入

    using N1::a;  //只有通过这种方式引入的变量或函数等才能直接使用,如果要使用该命名空间中的其他变量或函数还需采用1)中的方式使用

    int main(){

    cout<<a<<endl;

    return 0;}

    3)使用using namespace 命名空间名称引入

    using namespace N1;  //直接将命名空间中的所有变量、函数等引入,可以随便使用(不建议这样做)。

    int main(){

    cout<<a<<endl;

    return 0;}

    3.C++的输入和输出

    3.1 C++标准输入输出

    在C++中cout是标准输出、cin是标准输入,在使用cout标注输出和cin标准输入时需要包含<iostream>头文件和std标准命名空间。

    int main(){

    cout<<"hello world"<<endl; //控制台输出hello world并换行

    return 0;}

    3.2 C++标准输入输出的使用

    1)不需要控制输出格式

    using namespace std;

    int main(){

    int a = 10;

    cout<<a<<endl;  //10,不需要控制输出格式,自动确定输出格式

    cout<<"hello C++"<<endl;  //加双引号输出字符串

    return 0;}

    2)多变量输出

    using namespace std;

    int main(){

    int a = 10;

    char ch = 'C';

    cout<<"a = "<<a<<" ch = "<<ch<<endl; //一个输出可以输出多个变量,不同变量不需要控制输出格式

    return 0;}

    3)endl换行

    using namespace std;

    int main(){

    cout<<"hello world"<<endl;  //endl自动换行,字符串中也可以使用'\n'换行

    return 0;}

    4)“陷阱”

    using namespace std;

    int main(){

    char a = 'c';

    char* b = &a;

    cout<<a<<endl;   //输出c...随机值,b为char*存储的是变量a的地址输出b应该为a的地址,但是c++标准输出中默认将char*按字符串处理,因此访问了a的内容。

    return 0;}

    4.缺省参数和函数重载

    4.1 缺省参数

    4.1.1 缺省参数的概念

    缺省参数是声明或定义函数时为函数的参数指定一个默认值。在调用该函数时,如果没有指定实参则采用该默认值,否则使用指定的实参。注意:缺省参数不能在定义和声明时同时定义,只需要在函数声明时指定缺省参数值就可以。

    //.h文件

    int Add(int a = 1,int b = 1)

    //.cpp文件

    int Add(int a ,int b){

    return a+b;}

    //main函数

    int main(){

    Add();  //不指定参数调用函数

    Add(10);  //指定部分参数值,默认从左向右指定

    Add(10,10);  //指定全部参数值

    }

    4.1.2 缺省参数的类型

    1)全缺省参数

    函数的所有参数全为缺省参数称为全缺省参数。

    void testFunc(int a = 1,int b = 1,int c = 1){

    cout<<"a = "<<a<<endl;

    cout<<"b = "<<b<<endl;

    cout<<"c = "<<c<<endl;

    }

    2)半缺省参数

    函数的参数中,部分参数为缺省参数称为半缺省参数。半缺省参数中,缺省的参数必须是右侧的参数且不允许缺省参数和非缺省参数间隔出现同时缺省值必须是常量或者全局变量。

    void testFunc(int a,int b = 1,int c = 1){

    cout<<"a = "<<a<<endl;

    cout<<"b = "<<b<<endl;

    cout<<"c = "<<c<<endl;

    }

    4.2 函数重载

    4.2.1 函数重载的概念

    函数重载是函数的一种特殊情况,C++允许在同一作用域中声明几个功能类似的同名函数,这些同名函数的形参列表(参数个数 或 类型 或 不同类型的的出现顺序(如果参数类型相同顺序不同也不行))必须不同,常用来处理实现功能类似数据类型不同的问题。 

    int Add(int a,int b){

    return a+b;}

    //类型不同

    double Add(double a,double b){

    return a+b;}

    //参数个数不同

    int Add(int a,int b,int c){

    return a+b+c;}

    4.2.2 extern "c"

    有时候在C++工程中可能需要将某些函数按照C的风格来编译在函数前加extern "C",意思是告诉编译器,将该函数按照C语言规则来编译。比如:tcmallocgoogleC++实现的一个项目,他提供tcmallc()tcfree两个接口来使用,但如果是C项目就没办法使用,那么他就使用extern “C”来解决。

    extern "c" int add(int a,int b); //将add函数按照C语言规则编译

    4.2.3 面试题

    1)为什么C++支持函数重载而C语言不支持函数重载?

    在C/C++语言中,一个.c/.cpp文件要生成可执行文件需要经过预处理、编译、汇编、链接几个阶段。

    实际我们的项目通常是由多个头文件和多个源文件构成,而通过我们C语言阶段学习的编译链接,我们可以知道,【当前a.cpp中调用了b.cpp中定义的Add函数时】,编译后链接前,a.o的目标文件中没有Add的函数地址,因为Add是在b.cpp中定义的,所以Add的地址在b.o中。因此链接阶段就是专门处理这种问题,链接器看到a.o调用Add,但是没有Add的地址,就会到b.o的符号表中找Add的地址,然后链接到一起。那么链接时,面对Add函数,连接器会使用哪个名字去找呢?这里每个编译器都有自己的函数名修饰规则。由于Windowsvs的修饰规则过于复杂,而Linuxgcc的修饰规则简单易懂,下面我们使用了gcc演示了这个修饰后的名字。

    通过下面我们可以看出gcc的函数修饰后名字不变。而g++的函数修饰后变成【_Z+函数长度+函数名+型首字母】。

    结论:在c++中,编译器将c++程序中多个文件链接到一起时,对函数使用了【_Z+函数长度+函数名+类型首字母】修饰规则,使得相同的函数名在参数不同时有可以找到不同的函数地址。而在C语言程序中直接使用函数名,不会对函数名做任何修饰,因此如果存在同名函数,编译器不知道什么时候调用的那个函数。综上,c++支持函数重载,c语言不支持函数重载。

    2)下面两个函数能构成函数重载嘛?

    int add(int a,int b){

    return a+b;}

    int add(int a = 0,int b = 0){

    return a+b;}

    答案:不构成,构成函数重载的条件是函数名相同,参数的类型、数量、顺序等不同,在这两个函数中,参数的数量和类型完全相同,唯一的区别是一个使用缺省参数一个没有使用,而缺省参数不能作为函数重载的条件。

    3)C++中能否将一个函数按照C的风格来编译?

    答案:能,使用extern "c"

    5.引用

    5.1 引用概念

    c语言中指针类型实现了多个变量访问同一个地址,通样C++中有引用类型实现了“一个变量多个名称”,即多个变量访问一个地址空间。

    注意:引用不是新定义一个变量,而是给已存在变量取了一个别名,编译器不会为引用变量开辟内存空间,它和它引用的变量共用同一块内存空间。

    5.2  引用的定义和特性

    5.2.1  定义引用变量

    格式:类型& 引用变量名(对象名) = 引用实体

    void TestRef()
    {
        int a = 10;
        int& ra = a;//<====定义引用类型
    
        printf("%p\n", &a);//引用变量不会单独开辟空间,因此输出地址都是一样的
        printf("%p\n", &ra);
    }

    注意:引用类型必须和引用实体是同种类型的 

    5.2.2  引用的特性

    1)引用的特性

    1. 引用在定义时必须初始化(因为引用变量编译器不会给开辟空间,因此要求定义时必须初始化)
    2. 一个变量可以有多个引用
    3. 引用一旦引用一个实体,再不能引用其他实体

    void TestRef()
    {
            int a = 10;
            // int& ra; // 该条语句编译时会出错
            int& ra = a;
            int& rra = a;
            printf("%p %p %p\n", &a, &ra, &rra);
    }

    2)常引用

    void TestConstRef()
    {
            const int a = 10;
            //int& ra = a; // 该语句编译时会出错,a为常量
            const int& ra = a;
            double d = 12.34;
            //int& rd = d; // 该语句编译时会出错,类型不同
            const double& rd = d;
    }

    5.3  引用的使用

    5.3.1  引用类型做参数

    void Swap(int& left, int& right)
    {
            int temp = left;
            left = right;
            right = temp;
    }

    5.3.2  引用类型做返回值

    int& Count()
    {
            static int n = 0;
            n++;
            // ...
            return n;
    }

    注意:如果函数返回时,出了函数作用域,如果返回对象还未还给系统,则可以使用引用返回,如果已经还给系统了,则必须使用传值返回、

    5.3.3  传值和传引用性能分析

    以值作为参数或者返回值类型,在传参和返回期间,函数不会直接传递实参或者将变量本身直接返回,而是传递实参或者返回变量的一份临时的拷贝,因此用值作为参数或者返回值类型,效率是非常低的,尤其是当参数或者返回值类型非常大时,效率就更低。引用实则是原变量的一个别名,传引用相当于直接将该变量作为参数或者返回值,省去了临时拷贝的系统开销。

    注意:当局部变量做返回值时,如果局部变量不是静态局部变量时,不能使用该局部变量的引用作为返回值进行返回;同时,传参时我们只希望将参数值传过去不希望改变参数时将原变量值进行改变,这时也不能使用引用作为函数的参数。

    5.4  引用和指针的区别

    从语法层面理解,引用是变量的别名,引用变量不会开辟空间存储。从底层实现的角度,引用是使用指针实现的,也会想指针一样开辟空间。

    1)引用在定义时必须初始化,指针可以先定义后初始化。

    2)引用定义并初始化后,引用对象不能在改变;指针指向一个变量后还可以改变指向其他变量。

    3)引用对象不能为NULL;指针可以指向NULL

    4)sizeof一个引用变量时,结果为变量类型;sizeof一个指针是=时,32位系统下始终是4个字节,64位系统下始终是8个字节。

    5)引用进行自增自减,直接对引用对象进行操作;指针进行自增自减是将地址+1或-1.

    6)有多及指针但是没有多级引用。

    7)引用访问实体时由编译器处理;指针访问指针对象时需要显示解引用。

    8)引用比指针使用起来相对更安全。

    6.内联函数

    6.1  内联函数的概念

    以inline修饰的函数叫做内联函数,编译时C++编译器会在调用内联函数的地方展开,没有函数压栈的开销,内联函数提升程序运行的效率。

    6.2  内联函数的特性

    1)inline是一种以空间换时间的做法,省去调用函数额开销。所以代码很长或者有循环/递归的函数不适宜使用作为内联函数。

    2)inline对于编译器而言只是一个建议,编译器会自动优化,如果定义为inline的函数体内有循环/递归等等,编译器优化时会忽略掉内联。

    3)inline不建议声明和定义分离,分离会导致链接错误。因为inline被展开,就没有函数地址了,链接就会找不到。

    面试题(重点)

    C语言中宏的优点和缺点是什么?c++中是如何解决宏的缺点的问题的?

    答案:

    宏的优点:

    1.增强代码的复用性。例如:宏函数  2.提高性能。宏的处理机制是宏替换,不需要向函数变量那样压栈等系列复杂操作。

    宏的缺点:

    1.不方便调试宏。(因为预编译阶段进行了替换)
    2.导致代码可读性差,可维护性差,容易误用。
    3.没有类型安全的检查 。

    C++中使用内联函数代替宏函数,使用const修饰变量代替宏常量。

    7.C++11新内容

    7.1  auto关键字

    C++11中,auto不再是一个存储类型指示符,而是作为一个新的类型指示符来指示编译器,auto声明的变量必须由编译器在编译时期推导而得。

    int main()

    {

            int  a = 10;

            auto b = a;//编译器自动推导出b是int类型

            auto  c = 'a';//字符a赋值给c时,编译器自动推导出c是字符型

            cout<<typeid(b).name()<<endl;  //输出int

            cout<<typeid(c).name()<<endl;//输出char

    }

    注意:使用auto定义变量时必须对其进行初始化,在编译阶段编译器需要根据初始化表达式来推导auto的实际类型。因此auto并非是一种“类型”的声明,而是一个类型声明时的“占位符”,编译器在编译期会将auto替换为变量实际的类型。

    auto使用需要注意的问题

    1)用auto声明指针类型时,用auto和auto*没有任何区别,但用auto声明引用类型时则必须加&

    2)当在同一行声明多个变量时,这些变量必须是相同的类型,否则编译器将会报错,因为编译器实际只对第一个类型进行推导,然后用推导出来的类型定义其他变量。

    3)auto不能作为函数的参数

    4)auto不能直接用来声明数组

    3)为了避免与C++98中的auto发生混淆,C++11只保留了auto作为类型指示符的用法

    4) auto在实际中最常见的优势用法就是跟C++11提供的新式for循环,还有lambda表达式等进行配合使用。

    7.2  基于范围的for循环

    1)语法

    for循环后的括号由冒号“ :”分为两部分:第一部分是范围内用于迭代的变量,第二部分则表示被迭代的范围

    void TestFor()
    {
        int array[] = { 1, 2, 3, 4, 5 };
        for (auto e : array)  //e的初始值为1
            cout << array[e-1] << " ";
    }

    2)使用条件

    1. for循环迭代的范围必须是确定的;对于数组而言,就是数组中第一个元素和最后一个元素的范围;对于类而言,应该提供begin和end的方法,begin和end就是for循环迭代的范围。
    2. 迭代的对象要实现++和==的操作。(关于迭代器这个问题,以后会讲,现在大家了解一下就可以了)

    7.3  指针空置nullptr

    1. 在使用nullptr表示指针空值时,不需要包含头文件,因为nullptr是C++11作为新关键字引入的。
    2. 在C++11中,sizeof(nullptr) 与 sizeof((void*)0)所占的字节数相同。
    3. 为了提高代码的健壮性,在后续表示指针空值时建议最好使用nullptr。

     

     

     

     

     

     

     

    展开全文
  • python类方法中self关键字

    万次阅读 2018-08-30 14:55:05
    之前学python爬虫时候要把函数封装到类里面,写成类方法,知道在python类方法中...在python中,所有类都直接或间接继承自Object类,定义了类之后就定义了一个命名空间,里面定义属性可以通过类名来引用。新...

    之前学python爬虫的时候要把函数封装到类里面,写成类方法,知道在python的类方法中第一个参数应该是self,但对self代表的具体意义不甚了了。最近在看Java,对面向对象编程的了解更多了一点,终于彻底弄明白self到底是什么了。

    Python的类

    在python中,所有的类都直接或间接继承自Object类,定义了类之后就定义了一个命名空间,里面定义的属性可以通过类名来引用。新定义的类中有一些Object中有的属性,可以在其中定义其他变量或者函数。实例化之后会创建一个对象,该对象脱胎于类,并且其中的属性动态地和类中的属性产生关联:

    class A:
        pass
       
    a = A()
    

    这段代码创建了一个类A,并且对它进行了实例化,实例化之后的对象绑定为变量a。我可以看看A里面和a里面分别有什么:

    In [38]: dir(A)
    Out[38]:
    ['__class__',
     '__delattr__',
     '__dict__',
     '__dir__',
     '__doc__',
     '__eq__',
     '__format__',
     '__ge__',
     '__getattribute__',
     '__gt__',
     '__hash__',
     '__init__',
     '__init_subclass__',
     '__le__',
     '__lt__',
     '__module__',
     '__ne__',
     '__new__',
     '__reduce__',
     '__reduce_ex__',
     '__repr__',
     '__setattr__',
     '__sizeof__',
     '__str__',
     '__subclasshook__',
     '__weakref__']
    
    In [39]: dir(a)
    Out[39]:
    ['__class__',
     '__delattr__',
     '__dict__',
     '__dir__',
     '__doc__',
     '__eq__',
     '__format__',
     '__ge__',
     '__getattribute__',
     '__gt__',
     '__hash__',
     '__init__',
     '__init_subclass__',
     '__le__',
     '__lt__',
     '__module__',
     '__ne__',
     '__new__',
     '__reduce__',
     '__reduce_ex__',
     '__repr__',
     '__setattr__',
     '__sizeof__',
     '__str__',
     '__subclasshook__',
     '__weakref__']
    

    用dir函数输出A中和a中的属性后,我们可以看到A和a中的属性是一样的。我们可以向其中添加属性,添加属性时必须初始化:

    In [40]: A.b
    ---------------------------------------------------------------------------
    AttributeError                            Traceback (most recent call last)
    <ipython-input-40-ebcfc7dbf31a> in <module>()
    ----> 1 A.b
    
    AttributeError: type object 'A' has no attribute 'b'
    
    In [41]: A.b = 1
    

    现在我们可以看看A和a中的属性发生了什么变化:

    In [42]: dir(A)
    Out[42]:
    ['__class__',
     '__delattr__',
     '__dict__',
     '__dir__',
     '__doc__',
     '__eq__',
     '__format__',
     '__ge__',
     '__getattribute__',
     '__gt__',
     '__hash__',
     '__init__',
     '__init_subclass__',
     '__le__',
     '__lt__',
     '__module__',
     '__ne__',
     '__new__',
     '__reduce__',
     '__reduce_ex__',
     '__repr__',
     '__setattr__',
     '__sizeof__',
     '__str__',
     '__subclasshook__',
     '__weakref__',
     'b']
    
    In [43]: dir(a)
    Out[43]:
    ['__class__',
     '__delattr__',
     '__dict__',
     '__dir__',
     '__doc__',
     '__eq__',
     '__format__',
     '__ge__',
     '__getattribute__',
     '__gt__',
     '__hash__',
     '__init__',
     '__init_subclass__',
     '__le__',
     '__lt__',
     '__module__',
     '__ne__',
     '__new__',
     '__reduce__',
     '__reduce_ex__',
     '__repr__',
     '__setattr__',
     '__sizeof__',
     '__str__',
     '__subclasshook__',
     '__weakref__',
     'b']
    
    In [74]: A.b
    Out[74]: 1
    
    In [75]: a.b
    Out[75]: 1
    

    我们可以看到,在A中和它的实例化对象中现在都有了属性b,而且它们的值相等。
    如果我们给A的实例化对象中添加属性呢:

    In [44]: a.c = 2
    
    In [45]: hasattr(a, c)
    ---------------------------------------------------------------------------
    NameError                                 Traceback (most recent call last)
    <ipython-input-45-15d927c71e90> in <module>()
    ----> 1 hasattr(a, c)
    
    NameError: name 'c' is not defined
    

    竟然报错了,c没有定义,报错的原因是A的实例化对象a的命名空间中有c,但是公共命名空间中没有c,所以我们再试一次:

    In [58]: c = a.c
    
    In [59]: hasattr(a, 'c')
    Out[59]: True
    
    In [60]: hasattr(A, 'c')
    Out[60]: False
    

    我们可以看到,a中有c,但是A中并没有c。是不是因为c指向的是a.c所以A中没有呢:

    In [61]: b = a.b
    
    In [62]: hasattr(A, 'b')
    Out[62]: True
    

    确实是因为在类的实例化对象中添加的属性不会加入类中。

    我们接着看给A或a中加入函数属性会发生什么:

    In [78]: A.foo = lambda x : x + 1
    
    In [79]: A.foo(1)
    Out[79]: 2
    
    In [80]: a.foo(1)
    ---------------------------------------------------------------------------
    TypeError                                 Traceback (most recent call last)
    <ipython-input-80-7dc85fd7a693> in <module>()
    ----> 1 a.foo(1)
    
    TypeError: <lambda>() takes 1 positional argument but 2 were given
    

    python方法函数中的self关键字

    上面执行"a.foo(1)"语句时有个报错,说只需要一个参数,但是给了两个参数,这第二个参数是怎么来的,为什么A.foo(1)就不会出错。这里我们可以引出python类中的方法函数,方法函数指的是通过类的实例化对象调用的函数,方法函数的第一个形参表示类的实例化对象,通常写成self。执行a.foo(1)时就相当于执行A.foo(a,1),因为A.foo()中只有一个形参,传入的参数多于需要的参数,所以发生类型错误。
    我们在A的定义中重新定义foo:

    class A:
        def foo(self, n):
            print(n+1)
       
    a = A()
    

    现在我们在a中调用foo就不会有问题了:

    In [85]: a.foo(1)
    2
    

    我们也可以试试调用A.foo:

    In [86]: A.foo(a, 1)
    2
    

    总结

    python的类中定义函数时的self关键字跟python的方法函数有关,方法函数由类的实例化对象调用,需要把调用它的实例化对象传入方法函数中,self即是表示实例化对象的形参。

    展开全文
  • Rust 有问有答之 use 关键字

    千次阅读 2020-05-26 19:39:28
    using 指令为命名空间创建别名,或导入在其他命名空间中定义类型。 using static 指令导入单个类成员。 use用途是什么 类比using,use用途有: 用于引用某个外部模块 直接使用枚举值,而无需手动...
  • 习题 ...1.const关键字与宏定义区别是什么? 区别 宏定义 const关键字 发生阶段不一样 预处理 编译阶段 做事情不一样 字符串替换 类型安全检查 是否分配内存 不分配内存 分配内存 ...
  • 目录一、永远hello world为什么需要命名空间using关键字二、数据类型值类型引用类型指针类型三、方法参数列表 一、永远hello world 在学习任何一种语言时,我们最常见就是hello world了,通过输出hello world...
  •  变量名实质上一段连续存储空间的别名,一个标号(门牌号)  程序中通过变量来申请并命名内存空间  通过变量的名字可以使用存储空间 2. 什么是变量的引用  对一个数据可以使用引用“reference”,这C++对c...
  • 在学习了和使用了这么多年的PHP之后,您知道...1. 用于命名空间的别名引用// 命名空间include 'namespace/file1.php';use FILE1\objectA;use FILE1\objectA as objectB;echo FILE1\CONST_A, PHP_EOL; // 2$oA = ne...
  • 2.命名空间的作用:防止命名冲突 3.如何定义一个命名空间:namespace N1{变量、函数} 命名空间中的成员如何使用: a.N1::成员名字:当前命名空间在内容中使用少 b.using N1::b; c.using namespace N1; 缺省参数....
  • 命名空间的名称即这个类存放的路径 类文件的第一个类,则这个类的名字 也可以通过引用其他的命名空间找到其他的类来帮助这个类来实现更复杂的运算过程 一个类可以引用很多的命名空间 ...
  • 索引一种特殊的文件(InnoDB数据表上的索引空间的一个组成部分),它们包含着对数据表里所有记录的引用指针。索引的遵循原则:1、最左侧原则,表的最左侧的一列,往往数据不会发生改变,不影响其他列的数据;2、...
  • C++入门

    2020-05-21 08:48:01
    【本节目标】 命名空间 ...使用命名空间的目的对标识符的名称进行本地化,以避免命名冲突或名字污染namespace关键字的出现就是针对这种问题的。 定义命名空间,需要使用到namespace关键字,后面跟命
  • 不同之处如下:命名空间 namespce 加入、struct类型加强、所有C++函数和变量必须明确类型(以前c语言编译器默类型)、新增bool类型、三目运算符功能增强、const关键字功能增强、枚举功能增强 新增之处:加入...
  • 程序员成长之旅——初识C++什么是C++如何学习C++C++关键字C++命名空间命名空间的定义命名空间的使用C++的输入和输出缺省参数概念分类函数重载概念名字修饰(name Mangling)extern “C”引用概念特性常引用使用场景...
  • 14.3 是什么使类成为集合:IEnumerable 392 14.3.1 foreach和数组 392 14.3.2 foreach和IEnumerable 393 14.3.3 foreach循环内不要修改集合 396 14.4 标准查询操作符 397 14.4.1 使用Where()来...
  • 在书中,这一章节开头说的是自定义命名空间和使用命名空间,在以我目前有限经验来说,程序集就是一个类库经过编译之后,所生成一个在引用命名空间,进而使用该文件中已经定义好字段,属性以及方法文件,以...
  • c#單選題精選360題

    2018-12-17 11:39:25
    21、C#中导入某一命名空间的关键字是( a )。 a) using b) use c)import d) include 22、一般情况下,异常类存放在什么命名空间中?( b )。 a) 生成异常类所在的命名空间 b) System.Exception命名空间 c) System....
  • C++基本

    2021-01-27 11:29:04
    在我理解中,命名空间就像创建了许多文件夹,有逻辑地将变量、函数和类(什么是类?)归入其中,避免命名冲突(字面意思)。 namespace N1 { \\在命名空间中定义变量 int a; \\在命名空间中定义函数 int ...
  • C++入门基础

    千次阅读 多人点赞 2021-05-18 15:23:55
    C++发展史C++关键字(C++98)命名空间C++中输入和输出缺省参数函数重载引用内联函数auto关键字(C++11)基于范围for循环(C++11)指针空值nullptr(C++11) 什么是C++?  C语言结构化和模块化语言,适合处理较小...
  • C++入门知识点

    2021-06-17 15:21:38
    命名空间 C++输入和输出 缺省参数 函数重载 引用 内联函数 auto关键字 基于范围for循环 指针空值——nullptr 1.1什么是C++ **C语言结构化和模块化语言,适合处理较小规模程序。对于复杂问题,规模较大...
  • 什么是类:一种数数据结构,存储...C#中关键字(小写)不能作为方法名,类名,命名空间名等, static 静态namespaceusing 引用class 类string 字符new 创建对象 C#标识符 console.WriteLine("你好!")...
  • 你必须知道495个C语言问题

    千次下载 热门讨论 2015-05-08 11:09:25
    命名空间 1.30如何判断哪些标识符可以使用,哪些被保留了? 初始化 1.31 对于没有显式初始化变量初始值可以作怎样假定?如果一个全局变量初始值为“零”,它可否作为空指针或浮点零? 1.32 下面代码为...
  • 《你必须知道495个C语言问题》

    热门讨论 2010-03-20 16:41:18
    命名空间 15 1.30 如何判断哪些标识符可以使用,哪些被保留了? 15 初始化 18 1.31 对于没有显式初始化变量初始值可以作怎样假定?如果一个全局变量初始值为“零”,它可否作为空指针或浮点零? 18  ...
  • 命名空间 15 1.30 如何判断哪些标识符可以使用,哪些被保留了? 15 初始化 18 1.31 对于没有显式初始化变量初始值可以作怎样假定?如果一个全局变量初始值为“零”,它可否作为空指针或浮点零? 18  ...
  • 命名空间  1.30如何判断哪些标识符可以使用,哪些被保留了? 初始化  1.31 对于没有显式初始化变量初始值可以作怎样假定?如果一个全局变量初始值为“零”,它可否作为空指针或浮点零?  1.32 下面代码...
  • 命名空间 44 1.30 如何判断哪些标识符可以使用,哪些被保留了? 44 初始化 47 1.31 对于没有显式初始化变量初始值可以作怎样假定?如果一个全局变量初始值为“零”,它可否作为空指针或浮点零? 47 1.32 ...

空空如也

空空如也

1 2 3 4 5 ... 9
收藏数 164
精华内容 65
关键字:

引用命名空间的关键字是什么