• C++ Primer学习笔记(三) C++中函数是一种类型!!!


    C++中函数是一种类型!C++中函数是一种类型!C++中函数是一种类型!

    函数名就是变量!函数名就是变量!函数名就是变量!

    (---20160618最新消息,函数名不是变量名。。。囧)

    (---20160714最新消息,C++没有函数类型。。。囧)

    (---但是,我认为把它们当成类型和变量更容易理解!!!)

    重要的事情要说三遍。。。

    C++ Primer学习笔记(二)

    类的构造函数
    与类同名,且无返回类型。
    同类的成员函数一样,也可以在类中声明,在类外定义。
    格式
      类名(): 成员1(成员1初始化值), 成员2(成员2初始化值) { }
    以上,冒号至大括号中间的部分,称为构造函数的初始化列表,用于调用类成员的构造函数来初始化。
    没有在初始化列表中显式指定初始化的成员,将会隐式的初始化。
     
    如果没有显式的定义一个构造函数,那编译器会生成一个默认构造函数
    --建议只适用于仅包含类类型成员的类。
    默认构造函数不会初始化内置类型成员!
     
     
    类的一般使用方式:有类user,则user.h是声明,user.cpp是定义,成员函数通常放入user.cpp中。
     
     
    #include <iostream>
    #include <string>
     
    using namespace std;
     
    //test const
    int main(){
        //------------测试非引用------------
        int no=10;
        const int no2=no; //OK
        int no3=no2; //OK!
        //上面得出结论:非引用类型的赋值无所谓const 
     
     
     
        //------------测试引用------------ 
        int &noref=no;
        const int &noref1=no;
     
    //    int &no2ref=no2;
        const int &no2ref1=no2;
     
        int &no3ref=no3; 
        const int &no3ref1=no3;
        // 上面得出结论:const引用可以指向const及非const。但非const引用只能指向非const。
     
     
     
        //------------测试指针------------
        int *pno=&no;
        const int *pno_1=&no;//指向const的指针,可以指向非const 
     
    //    int *pno2=&no2;//指向非const的指针,只能指向非const 
        const int *pno2_1=&no2;
     
        int *pno3=&no3;
        const int *pno3_1=&no3;
        // 上面得出结论:见备注    
     
     
        return 0;
    }
     
    //我擦,有谁能告诉我int怎么转成string吗?例如姓名年龄 一起输出。
     
     
    如果两个函数声明的返回类型和形参表完全匹配, 则将第二个函数声明视为第一个的重复声明。如果两个函数的形参表完全相同,但返回类型不同,则第二个声明是错误的。

    形参与 const 形参的等价性仅适用于非引用形参。有 const 引用形参的函数与有非 const 引用形参的函数是不同的。类似地,如果函数带有指向 const 类型的指针形参, 则与带有指向相同类型的非 const 对象的指针形参的函数不相同。

    注意:函数名也是变量,所以也存在被屏蔽的可能。--函数是一种类型!!!
    例如:有个init(),而局部变量int init=0;则会屏蔽掉init()!!!
    即:局部变量能屏蔽掉同名函数!!!
    同理:局部声明的函数,将屏蔽外部声明的函数。。。屏蔽所有同名的函数,包括重载的。
     
    在 C++ 中,名字查找发生在类型检查之前。
    仅当形参是引用或指针时,形参是否为 const 才有影响。
    可基于函数的引用形参是指向 const 对象还是指向非 const 对象, 实现函数重载。将引用形参定义为 const 来重载函数是合法的,因为编译器可以根据实参是否为 const 确定调用哪一个函数。

    重复强调, 编译器可以判断: 如果实参是 const 对象,则调用带有 const* 类型形参的函数;否则,如果实参不是 const 对象, 将调用带有普通指针形参的函数。

    但是,不能基于指针本身是否const来实现函数重载!
    f(int *);
    f(const int *);//redeclaration
    因为const的是指针,而非指针所指向的类型。在上述两种情况中, 都复制了指针, 指针本身是否为 const 并没有带来区别。
     
     
    函数的指针,是指向函数类型
    像其他指针一样,函数指针也指向某个特定的类型--函数类型。
    函数类型由其返回类型以及形参表确定, 而与函数名无关
    例如:bool (*pf) (const string &, const string &); // pf的括号是必须的
    这个语句将 pf 声明为指向函数的指针,它所指向的函数带有两个 const string& 类型的形参和 bool 类型的返回值。

    可以使用typedef简化函数指针的使用
    typedef bool (*cmpFcn) (const string &, const string &);
    上面定义了一个指向函数的指针类型的名字:cmpFcn。
     
     
    在引用函数名但又没有调用该函数时,函数名将被自动解释为指向函数的指针。
    所以,可以使用函数名对函数指针进行初始化或赋值。
    cmpFcn pf1=0;    //ok
    cmpFcn pf2=lengthCompare;    //ok
    pf1=lengthCompare;    //ok
    pf2=pf1;    //ok   
    直接引用函数名,等效于在函数名上取地址。
    cmpFcn pf1=lengthCompare;
    cmpFcn pf2=&lengthCompare;
     
    不同类型的函数指针不能转换!!!
     
    通过函数指针可以调用函数,而且不需要显式解引用操作
    lengthCompare("hi", "bye"); //直接调用函数
    pf("hi", "bye"); //隐式解引用!
    (*pf)("hi", "bye"); //显式解引用!
     
    函数指针作为形参!卧槽,感觉要进入lambda了!
    void func(const string &, const string &, bool(const string &, const string &)); //隐式
    void func(const string &, const string &, bool (*)(const string &, const string &)); //显式
     
    函数指针作为返回值!卧槽,这绝对是lambda!
    int (*ff(int))(int*,int); //QNMD
    其中:ff(int) 是函数,返回 int (*)(int*,int),也就是返回函数指针。
     
    #include <iostream>
    #include <string>
    using namespace std;
     
    int strCmp(const string&, const string&);
    int xxx(const string&, const string&);
     
    //函数指针
    int main(){
        string str1="hehe";
        string str2="abc";
     
        cout<<"strCmp(str1, str2):"<<strCmp(str1, str2)<<endl;
     
        //函数指针 
        int (*ext)(const string&,const string&); //(*strCmp)的括号是必须的。如果声明:int *strCmp(const string&, const string&) 
     
        typedef int (*fp)(const string&, const string&);//类似声明
        fp p0=0;
        cout<<"p0:"<<p0<<endl;
        fp p1=strCmp;
        fp p2=p1;
        p0=p2;
     
        cout<<"p0("---", "xxxxxxx")"<<p0("---", "xxxxxxx")<<endl;    
        cout<<"p1(str2, str1):"<<p1(str2, str1)<<endl;     //why?
        cout<<"p2(str2, str1):"<<p2(str2, str1)<<endl; //why?    
     
        fp p3=xxx;
        cout<<"p3:"<<p3<<endl;//why 1?
        cout<<"p3("a", "b"):"<<p3("a", "b")<<endl;
     
     
        ext =xxx;
        cout<<"ext:"<<ext<<endl;//why 1?
        cout<<"ext(str1, str2):"<<ext(str1, str2)<<endl;
     
     
        //结论:type (*pf)(parameter list)就已经定义了一个函数指针pf。
      //typedef可以定义函数指针的类型,而非函数指针。该类型可以定义指针。
      //0函数指针输出0;其他则输出1。
      //通过函数指针可以直接调用函数:只要后面跟上实参列表即可!函数指针会隐式的解引用--当然也可以显式的解引用!
     
     
        return 0;
    } 
     
    int strCmp(const string &str1, const string &str2){
        return str1.size()-str2.size();    
    }
     
    int xxx(const string &str1, const string &str2){
        return 11111;
    }
     
     
    而所谓返回函数指针,或者作为形参,其实都是操作函数指针变量---需要注意,只是返回,不是调用函数!!
    而且,建议配合typedef 使用,否则难明白。
    例如:
      int (*func(p.l.))(p.l. of fp);  //p.l. = parameter list;   fp=function pointer
    可以先定义:typedef  int (*fp)(p.l. of fp);
    然后,前面就可以写成:fp func(p.l.);
     
    注意:允许将形参定义为函数类型,但函数的返回类型则必须是指向函数的指针,而不能是函数!!!
    具有函数类型的形参所对应的实参,将被自动转换为所指向相应函数类型的指针。但是,当返回的是函数时,同样的转换操作无法实现!
    typedef int func(p.l);//这里的func是函数类型,不是函数指针!所有int xxx(p.l)形式的函数!
    void f1(func); //ok  函数类型可以作为形参
    func f2(int); //error 函数类型不能作为返回值!
    func *f3(int); //ok 函数类型指针可以作为返回值(其实就是函数指针)
    上面的关键是:函数是一种类型!!!函数名是变量!!!
  • 相关阅读:
    java数据类型
    如何判断数组
    git 常用命令
    如何配置 ESLint 工作流
    Lambda表达式和函数式接口
    面向对象(多态与内部类)
    面向对象(封装与继承)
    面相对像(基础)
    break;怎么跳出外部循环
    面向对象(类与对象)
  • 原文地址:https://www.cnblogs.com/larryzeal/p/5593460.html
Copyright © 2020-2023  润新知