精华内容
下载资源
问答
  • 同名函数之间的关系

    2019-08-02 15:30:47
    在C++中同名函数存在如下三种关系: 函数重载/重定义:指的是在同作用域下,由函数参数列表(参数类型、参数个数、参数顺序)提供支持的多个同名函数同时存在的一种关系; int sum(int a,int b) { return a+b; } ...

    在C++中同名函数存在如下三种关系:

    • 函数重载/重定义:指的是在同作用域下,由函数参数列表(参数类型、参数个数、参数顺序)提供支持的多个同名函数同时存在的一种关系;
    int sum(int a,int b)
    {
    	return a+b;
    }
    
    int sum(int a,int b,int c)
    {
        return a+b+c;
    }
     
    double sum(double a,double b)
    {
    	return a+b;
    }
    
    
    float sum(float a,float b)
    {
    	return a+b;
    }
     
    注意一点:函数返回值并不对函数重载提供支持,因为在函数的调用点与函数匹配时只能推演函数名、函数参数列表,看不见返回值类型。另外常函数也是函数重载的一种形式。
    • 隐藏:在类的不同作用域下,准确的说是基类与派生类、父类与子类的关系下,子类中如果有和父类同名的函数,则继承之后的子类的同名函数完全会将该类的基类部分同名函数隐藏起来,简单来说就是基类的同名函数存在,但是派生类对象不可见的情况,派生类对象如果调用该同名函数,则调用的是派生类中的那个同名函数;当然类的成员变量也遵循这种隐藏关系;如果可以去调用基类中定义的同名函数的话,就要在函数名前加上基类作用域Base::函数名();
    class  A{
    public:
        A(int a):a(ma){}
    
          void show()
        {
           cout<<"a="<<a<<endl;
        }
    public:
         int ma;
    };
    
    
    class  B: public A{
    public:
        A(int a,int b):A(ma),b(mb){}
    
          void show()
        {
           cout<<"b="<<a<<endl;
        }
    public:
         int ma;
         int mb;
    };
    
    int main()
    {
      B  b(4,5);
      b.show();//5
      b.A::show();//4
      return 0;
    }
    
    
    
    • 覆盖/重写:此关系在函数同名基础上多一个条件-------------基类与派生类中同名函数要求参数相同且基类函数前必须有virtual关键字,函数的返回值也要相同。覆盖这一特性是由虚表提供支持的,一个类不管有多少虚函数,只生成一个虚函数指针,虚函数指针指向虚函数表,虚函数表中存放的是函数入口地址,该类的每个对象共用一个虚函数指针。

           在指针调用虚函数且对象完整时才发生多态,覆盖、重载属于方法的多态性,而对象的多态性体现在基类与派生类的转型:

                     向上转型,目的是限制对于子类对象特有属性的访问 Animal a = new Cat();

                     向下转型,目的是为了访问子类的特有属性 Cat c = (Cat)a;

    #include<iostream>
    using namespace std;
     
    class Base
    {
    public:
    	virtual void fun(){}  //成为虚函数的三个前提条件:依赖对象调用、对该函数可以取地址;比如说一般的成员方法和析构函数;
        int a;
    };
    
     class Derive:public Base
    {
    public:
        void fun()
        {
           cout<<"-----"<<endl;
        }
    int b;
    
    };
    void main()
    {
    	  Derive d;//生成一个派生类对象
              Base*pb=&d;//基类指针指向派生类对象
    }

    内存布局:

    • 纯虚函数:虚函数写成void  show()=0;这种形式的时候虚函数变成纯虚函数,所在的类成为抽象类,抽象类中纯虚函数在派生类中必须实现,否则派生类还是抽象类,不能生成对象,没有意义。抽象类不能实例化对象,但是允许基类的指针或者引用指向派生类的对象,此时应该将析构函数也写成虚函数,不然被指向的对象资源不能完全释放。
    • 虚继承:虚继承为的是解决访问变量或者成员方法不明确的问题;
    #include <iostream>
    using namespace std;
    class A
    {
    public:
    	int num;
    	A()
    	{
    		num=100;
    		cout<<"A"<<endl;
    	}
    	~A()
    	{
    		cout<<"~A"<<endl;
    	}
     
     
    };
     
    class B:virtual public A //虚继承
    {
    public: 
    	B()
    	{
    		cout<<"B"<<endl;
    	}
    	~B()
    	{
    		cout<<"~B"<<endl;
    	}
    };
     
    class C:virtual public A //虚继承 
    {
    public: 
    	C()
    	{
    		cout<<"C"<<endl;
    	}
    	~C()
    	{
    		cout<<"~C"<<endl;
    	}
    };
    class D:public B,public C
    {
    public: 
    	D()
    	{
    		cout<<"D"<<endl;
    	}
    	~D()
    	{
    		cout<<"~D"<<endl;
    	}
    };
    
    菱形继承明显的问题就是造成访问的不明确;
    
    int main()
    {
    	D d;
    	//cout<<d.num<<endl;//error:访问不明确;没加virtual前;
    	//第一种方案:清楚的表明作用域,以免出现歧义:
    	//cout<<d.B::num<<endl;
    	//cout<<d.C::num<<endl;
    	//第二种方案:加上virtual后,就没有歧义了,B和C都指向同一份A;
    	cout<<d.num<<endl;//加上virtual OK
    	system("pause");
    	return 0;
    }

     

    展开全文
  • 简述C++类继承的关系,运用过程中涉及到的初始列表,类内部使用其他类等。

             C++类是用户自定义的抽象数据类型,其在声明期间不分配内存,只有当这个类实例化后才分配内存。通过继承,子类不仅可以拥有新的属性和方法,还拥有父类的所有属性和方法。C++类继承的方式分为公有继承(public)、保护继承(protected)和私有继承(private),根据继承方式的不同,实现对子类和父类成员变量和方法的访问控制。当采用不同的继承方式后父类原来的变量在子类中的访问性如表格所示:

      父类成员属性

    子类继承

    方式

     

    Public

     

    Protected

     

    Private

    Public

    Public

    Protected

    -

    Protected

    Protected

    Protected

    -

    Private

    Private

    Private

    -

    *注:表中“-”表示在子类不可见

    总结:

    Public修饰的成员变量、方法,在类的内部、类的外部都能使用

    Protected修饰的成员变量、方法在类的内部使用,在继承的子类的中可用

    Private修饰的成员变量、方法只能在类的内部使用,不能在类的外部使用

    继承的内存分配:

    对于派生类B,其内存中首先给继承自父类的数据成员分配内存,其次是自己的数据成员。


     

    类型的兼容性原则

            指在任何需要基类对象的地方都可以使用公有派生类的对象来替代。通过公有继承,派生类得到了基类中除构造函数、析构函数之外的所有成员

    所指的兼容性规则中所指的替代包括以下情况:

    子类对象可以当做父类对象使用

    子类对象可以直接赋值给父类对象

    子类对象可以直接初始化父类对象

    父类指针可以直接指向子类对象

    父类引用可以直接引用子类对象

     

    类继承中的构造函数和析构函数调用顺序:

             利用子类声明一个子类对象时,构造函数和析构函数的调用顺序如下:

             父类Constructor→子类Constructor

             子类Deconstructor→父类Deconstructor

     

    构造函数参数初始化列表:

            构造函数的执行阶段可以分为初始化阶段和计算阶段,初始化阶段先于计算阶段执行,计算阶段及执行构造函数的函数体部分。

            对于普通内置类型的初始化在哪个阶段执行没什么差别,但是以下三种情况必须使用初始化列表:

    1、类的成员变量是对象的时候,通过初始化列表显式调用该对象(父类)的有参构造函数初始化该类的私有成员;

    2、需要初始化const修饰的成员变量;

    3、需要初始化引用成员变量。

           参数列表的初始化顺序与数据成员在类中的声明顺序有关,而与初始化列表中的顺序无关。

     

    在类中声明父类对象的混合情况下构造函数调用顺序:

    1、根据继承顺序依次调用父类和子类的构造函数;

    2、调用初始化列表中的显式调用的构造函数。

    【一个例子】

    #include <iostream>
    #include <stdlib.h>
    using namespace std;
    
    class Object
    {
    public:
    	Object(int _a)
    	{
    		a = _a;
    		cout << "Object Constructor..." << a << endl;
    	}
    
    	~Object()
    	{
    		cout << "Object DeConstructor..." << endl;
    	}
    private:
    	int a;
    };
    class Parent:public Object
    {
    public:
    	Parent(int _b,int _c):Object(_b)
    	{
    		b = _b;
    		c = _c;
    		cout << "Parent Constructor..." << b<<" "<<c<< endl;
    	}
    	~Parent()
    	{
    		cout << "Parent DeConstructor..." << endl;
    	}
    protected:
    private:
    	int b;
    	int c;
    };
    
    class Child: public Parent
    {
    public:
    	Child(int _d):Parent(_d*4,_d*2),a(_d),d(_d),obj(d*3),obj2(d*5)
    	{
    		cout << "Child Constructor..."<<d << endl;
    	}
    
    	~Child()
    	{
    		cout << "Child DeConstructor..." << endl;
    	}
    private:
    	const int a;
    	int d;
    	Object obj;
    	Object obj2;
    };
    
    void playmain()
    {
    	Child c1(1);
    }
    int main()
    {
    	playmain();
    	system("pause");
    	return 0;
    }
    运行结果如下:


     

     

    类继承中同名变量和同名函数调用规则:

             利用子类对象调用同名变量和同名成员函数时,默认情况下调用子类的变量和函数,当要调用父类的变量和函数时,利用域作用符(::)显式调用

             A 继承于B ,A、B都有函数print()

             B b1;

            b1.A::Print();


    展开全文
  • 先说下预解析的含义,在写js代码调用函数的时候,无论你是在调用位置的前面或者后面声明函数,都可以正常调用,原因是,JavaScript碰到script标签,会将var变量(注意是var)声明和函数声明(注意是声明)提升到当前...

    先说下预解析的含义,在写js代码调用函数的时候,无论你是在调用位置的前面或者后面声明函数,都可以正常调用,原因是,JavaScript碰到script标签,会将var变量(注意是var)声明和函数声明(注意是声明)提升到当前作用域最前面。

    要想搞懂预解析,先记住结论:

    变量的提升,指的是声明的提升,赋值(初始化)并不会提升

    接下来 就对着这个结论看一些例子:

    例1:

    console.log(num); //undefined
        var num = 2;

    变量声明提升,赋值不提升,所以上述代码相当于:

    var num;
    console.log(num);
    num = 2;

    例2:

    var num = 2;
    var num;
    console.log(num); //2

    是不是以为是undefined呢?千万别忘了变量是会提升的,看下面代码就明白为什么是2了:

    var num;
    var num;
    num = 2;
    console.log(num);

    这里有个问题,看下面代码:

    function f() {}
    var f
    console.log(f); //function f() {}

     按理说,这里应该是undefined,结果明显不是,这里个人以为可以理解成,变量的声明提升后会在函数前面

    再将代码作如下修改:

    function f() {
    console.log(num); // undefined
    }
    var num
    

    这里函数里面能访问到num,证明变量的声明会在函数声明之前

    这个问题是个人的理解,有疑问的读者也可以去查些资料。 


    例3:

    var f = function() {
       console.log(1)
    }
    function f() {
      console.log(2)
    }
    f(); // 1

    这个例子结果是1的原因,可以看下面的代码:

    var f;
    function f() {
       console.log(2)
    }
    f = function() {
      console.log(1)
    }
    f();

    例4:

    f(); // 2
    var f = function() {
      console.log(1)
    }
    function f() {
      console.log(2)
    }

    这个例子和前一个只是函数调用位置发生了改变,结果也变了,可以尝试自己按照步骤一步步重新写在纸上,结果如下:

    var f;
    function f() {
      console.log(2)
    }
    f();
    f = function() {
      console.log(1)
    }

    例5:

    f(); //报错
    var f = function(){
       console.log('k')
    }

    这个例子应该很简单,只是将例1中的变量换成了函数:

    var f;
    f();
    f = function(){
      console.log('k')
    }

    调用一个未赋值的函数,当然会报错,注意一下,这个例子,将函数表达式换成函数声明就不会报错了,因为函数声明会提升,这也是我们常用函数声明的一个原因,可以在任何位置调用。


    例6:

    var num = 2;
    function f() {
      num = 1;
      console.log(num); //1
      return
      var num = 3;
    }
    f();
    console.log(num) //2

    return后面的语句虽然不会执行,但是变量还是会提升:

    var num = 2;
    function f() {
       var num
       num = 1;
       console.log(num); //1
       return
       num = 3;
    }
    f();
    console.log(num) //2

    例7:

    console.log(num);// 报错
    num = 2;

    我们开篇就说过,只有var会提升,隐式全局变量并不会提升,所以结果和例1不同,并不是undefined


     

    展开全文
  • 同名函数的选择 同名函数的情况,可以出现于函数重载或者有模板函数的情况下,弄清各个函数的调用优先级以及报错的情况有必要 void may(int); float may(float, float y=3); void may(char); char * may...

    同名函数的选择

    • 同名函数的情况,可以出现于函数重载或者有模板函数的情况下,弄清各个函数的调用优先级以及报错的情况有必要
    void may(int);
    
    float may(float, float y=3);
    
    void may(char);
    
    char * may(const cahr & );
    
    template<class T> void may(const T &);
    
    template<class T> void may(T *);

    编译器选择匹配的函数顺序如下 :
    1. 完全匹配。参数列表和返回类型完全匹配,不需要任何转化。其中,常规函数>显示具体化>普通模板.
    2. 提升转换。形参和实参并非完全匹配,带入的实参会自动转化为形参的类型,精度不会改变,是安全的转化。char short 转为 int, float 转为double
    3. 标准转化。可能会丢失精度。int 转为 char ,long 转为double。

    完全匹配 和最佳匹配

    • 以下的转化都可以视为完全匹配,其中type 泛指任何一种类型。
    实参形参
    typetype &
    type &type
    type []*type
    type (arguement-list)type * (arguement-list)
    typeconst type
    typevolatile type
    type *const type
    type *volatile type*

    所以,以下4个都是完全匹配,从报错中明显可见

    void test(int);
    void test( const int);
    void test(int &);
    void test(const int &);
    

    image

    • 只有上面的第1 、2个,由于完全匹配将会编译出错,这个并不难理解,编译器发现了两个都可以匹配的不知道匹配哪个。

    image

    • 只有第3、4个,编译没有任何问题。并且可以看出,选择的是无const 版本,对于引用类型和指针类型都是这样。而对于实参是const 的类型, 由于非const指针不能指向const,选取const形参函数是理所应当的。
    void test(int &)
    {
        cout << " I'm void test(int &);" << endl;
    }
    void test(const int &)
    {
        cout << " I'm void test(const int  &);" << endl;
    }
    
    void test(int *)
    {
        cout << " I'm void test(int *);" << endl;
    }
    void test(const int *)
    {
        cout << " I'm void test(const int *);" << endl;
    }
    int main()
    {
        int a = 5;
        const int b = 10;
    
        test(a);
        test(b);
    
        test(&a);
        test(&b);
    
        cin.get();
        return 0;
    }

    image

    自定义匹配

    • 也就是使用者指定使用哪个,比如虽然有模板和普通函数,由于某些原因,我希望编译器使用模板。
    void cal(double x, double y)
    {
        cout << "int cal(int x, int y)  :" <<  x+y <<endl;
    }
    
    template <typename T>
    void cal(T x, T y)
    {
        cout << "T cal(T x, T y)   :" <<x+y <<endl;
    }
    
    int main()
    {
        double  x = 1.6; 
        double y = 2.7;
    
        cal(x,y);
        cal<>(x, y);
        cal<int >(x, y);
        cin.get();
    
        return 0;
    }

    image

    从结果看,确实根据使用者需要,调用了相应的函数。

    无法确定的模板变量类型处理

    template <typename T1, typename T2>
    void test(T1 x ,T2 y)
    {
        A =x+y;
    }

    对于上述的代码将会出现一个问题,无法预先知道A的类型。可以使用函数decltype()

    decltype(x+y) A =x+y;//根据x+y的类型确定变量类型,由编译器确定
    
    //对于函数返回类型
    
    template <typename T1, typename T2>
    auto test(T1 x ,T2 y) ->decltype(x+y);
    

    1、volatile进行优化,强制编译器从硬件中读取。虽然程序没有改变某个内存的值,但是硬件可能根据条件使内存变化,比如串口接受数据

    2、mutable 指出,即使结构体或者变量被定义为const类型,内部的某个参数仍然可变。

    struct data
    {
        mutable int a;
        int b;
    }
    
    const data x ={12};
    x.a=5;       //这是可行的

    3

    名空间

    定义一个名空间

    namespace Jack{
        double x;
        int y;
    }
    • 为名空间扩展内容;为名空间内的函数实现定义
    namespace Jill{
        char *goose (const char *);
    }
    
    namespace Jack{
        void test()
        {
        }
    }
    • 名空间作用域解析,
    Jack::x=3.5;
    Jack::y=8;
    using声明 和 using编译指令
    • 为了免去每次使用名空间解析的繁琐,可以使用using 一次性声明某个名空间内的内容。使得解析后的内容的可用范围在使用using声明块内。
    int main()
    {
        using Jill::test;
    }
    • 使用using 编译指令使得对应名空间内内容均可用
    using namespace Jill;
    展开全文
  • 基类、派生类的同名函数

    千次阅读 2018-08-02 20:19:14
    3、子类与父类的函数同名时,子类会覆盖掉父类所有的同名函数,如下例,子类的一个func_0( ),把父类的func_0( )和func_0(int)都覆盖掉了。 4、发生覆盖时,父类指针指向子类对象时,访问的全部都是父类的同名成员...
  • c 处理同名函数

    千次阅读 2011-07-19 07:37:54
    放到结构体里面,动态加载嘛,程序初始的时候,加载一遍, 比如,ibm函数全部放到ibm_func, 但是,sun也有自己的实现,那么,放到另一个结构体里面, 当然,结构体只是为了管理方便,思路是用指针保存起来, 原文...
  • 在c++中的继承中,如果基类声明了一个函数为虚函数,那么在派生类中不用声明同名函数为虚函数(需要加virtual)也可以实现该函数为虚函数。  派生类继承了基类的属性,同名函数被视为与基类具有相同属性的函数。...
  • Linux 动态库同名函数处理原则

    千次阅读 2014-08-04 16:23:07
    问:有一个主执行程序main,其中实现了函数foo(),同时调用动态库liba.so中的函数bar(),而动态库liba.so中也实现了foo()函数,那么在执行的时候如果在bar()中调用foo()会调用到哪一个?在main()中调用呢?  ...
  • C++ 实现 根据字符串 调用同名函数

    千次阅读 2012-08-24 18:35:03
    需求: 希望根据用户的输入调用同名函数。 因为想写各种 if else,所以就建立一个key为string,value为函数指针的map,根据string的值调用相应的函数。 以下代码在gcc 3.4.6下测试通过。 下面是代码...
  • 背景:在开发图形挖矿软件时,需要调用非界面软件接口。思路1,编译ccminer及cpuminer成可执行文件,直接调用;...难点:由于两个动态库存在大量同名变量及函数,直接改函数名十分耗时。 解决方法:...
  • c++同名函数----重载、隐藏、覆盖

    千次阅读 多人点赞 2018-08-21 12:55:34
    函数的返回类型可以相同也可以相同。 仅仅返回类型不同足以成为函数的重载。 相同的范围(在同一个类中); virtual 关键字可有可无。 为什么需要函数重载? 试想如果没有函数重载机制,如在C中,你必须要...
  • 函数名相同 作用域相同 函数参数不同 class Base { public: //这两个函数构成重载 void show() { cout << "Base::void show()" << endl; } void show(int i) { cout << "virtual ...
  • 一般函数同名:当某个函数func()在基类和派生类中都有定义时,派生类中的函数func()将修改从基类继承来的函数func(),如果非要从派生类中访问基类的函数func(),有两种方法:一、定义基类指针,让基类指针...
  • 首先来看一下派生类和基类成员...如果派生类内部成员或派生类的对象需要访问基类继承来的同名函数,则必须在同名函数前加上"基类名::"进行类名限定。如果基类内部成员函数或基类对象访问同名成员,访问的一定是基类的同
  • 开始我没有细想,就说可能会出错吧,可是等我实验完了发现页面没有任何脚本错误提示,而且程序也运行了,只是对同名函数的调用执行了位置靠后的一个。  回头仔细一想,这个结果完全可以接受,因为脚本在页面里本身...
  • C++中static定义静态变量时,只在程序启动的时候初始一次,后续在初始,且定义的该变量只能在该文件中使用,而能夸文件使用。要想在其它文件中使用全局变量,则需要在定义的文件中使用extern关键字进行定义...
  • 当模板函数同名的普通函数重载时,其调用顺序是怎样的呢?让我们实验一把,看一看它的调用顺序: 示例代码如下: #include "iostream" using namespace std; void mySwap(int a, char b) { cout <<...
  • C++函数匹配顺序C++语言引入模板机制后,函数调用的情形显的比C语言要复杂。当发生一次函数调用时,如果存在多个同名函数,则C++编译器将按照如下的顺序寻找对应的函数定义。
  • c++ 构造函数初始过程

    千次阅读 2018-09-14 11:26:52
    每个类都会为它的对象定义初始的方式,用一个或几个特殊的函数去控制对象的初始,我们把这些特殊的函数叫做 构造函数。... 答: 构造函数函数名与类名同名,没有返回值类型,有一个参数列表(...
  • 文章目录1 子类定义父类同名成员2 子类定义父类同名函数3 小结 1 子类定义父类同名成员 子类中可以定义父类的同名成员 子类中的成员将隐藏父类中的同名成员 父类中的同名成员依然存在于子类中,需要用作用域分辨符...
  • 函数模板与同名的非模板函数重载时候,调用顺序: 寻找一个参数完全匹配的函数,如果找到了就调用它寻找一个函数模板,将其实例,产生一个匹配的模板函数,若找到了,就调用它若1,2都失败,再试一试低一级的对...
  • 构造函数各其他函数之间的一个重大差别是构造函数不能返回值,因此对它们不可以指定返回类型.通常情况下,构造函数声明为public.关于Program Language更多讨论与交流,敬请关注本博客和新浪微博songzi_tea.
  • 众所周知,三层的D层主要是对数据的处理,而...首先是一个带参数返回值为bool的函数,在写一个带参数返回值为bool的函数,还有一个带参数返回值为datatable的函数,最后是一个带参数返回值为datatable的函数,如果
  • 能声明为虚函数函数

    千次阅读 2017-03-13 20:08:22
    使用虚函数时,有两点要注意: (1)只能用virtual声明...(2)一个成员函数被声明为虚函数后,在同一类族中的类就能再定义一个非virtual的但与该虚函数具有相同的参数(包括个数和类型)和函数返回值类型的同名函数
  • C语言为什么支持函数重载

    千次阅读 2019-04-30 17:55:25
    函数重载 在我们中国的文化中,一个词可能是有多种含义,在这种情况下就可以通过上下文来判断这个词到底是什么意思,在这里我们就可以理解为这个词被重载了。 例:又是晴朗的而又美好的一天,可是小明的妈妈却让...
  • 为什么可以在同一个函数内定义多次静态同名变量呢?这很违反我之前的认知,以为变量名就相当于我分配的这块地址的入口一样,定义3个同名变量不会搞出大事吗?编译器还报错,无语..... 我加了很多的printf来测试,...
  • 如题,我知道第一个rectangle是构造函数,所以要与类同名,然后可以初始赋值,为什么另一个程序setpoint明明不是构造函数,但是可以做赋值处理,然后程序不会报错呢?我把rectangle类里的rectangle函数改成re却是...
  • 一、构造函数 C++提供了构造函数(constructor)来处理对象的初始。 在建立对象时自动执行。 构造函数的名字必须与类名同名,它具有任何类型,返回任何值。
  • 硬盘函数不正确怎么解决

    万次阅读 2017-11-30 09:56:03
    硬盘函数不正确是因为这个盘的文件系统内部结构损坏,导致这个盘无法正常打开。要想恢复里面的数据一定要注意不要直接格式。具体的恢复方法可以看下文了解 工具/软件:极光数据恢复软件 数据恢复方法: ...
  • 类和函数模板特例

    千次阅读 2016-08-30 20:37:07
    引入原因:编写单一的模板,它能适应大众,使每种类型都具有...函数模板特例:必须为原函数模板的每个模板参数都提供实参,且使用关键字template后跟一个空尖括号对,表明将原模板的所有模板参数提供实参。templa

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 161,977
精华内容 64,790
关键字:

不同名函数化同名函数