精华内容
下载资源
问答
  • python中format函数

    万次阅读 多人点赞 2019-05-14 12:07:45
    python中format函数用于字符串的格式化 通过关键字 1. print('{name}{option}'.format(name="谢某人",option="写代码")) 结果:谢某人写代码 通过位置 1. print('name={} path={}'.format('zhangsan', ...

    python中format函数用于字符串的格式化


    通过关键字

    1.

    print('{name}在{option}'.format(name="谢某人",option="写代码"))

    结果:谢某人在写代码 


    通过位置
    1. 

    print('name={} path={}'.format('zhangsan', '/')

    结果:name=zhangsan path=/

    2. 

    print('{1}在{0}'.format('写代码','谢某人'))

    3. 

    print('{0}在{1}'.format('谢某人','写代码'))

    结果:谢某人在写代码


    填充和对齐^<>分别表示居中、左对齐、右对齐,后面带宽度

    print('{:^30}'.format("zhangsan")) # 居中
    print('{:>30}'.format("zhangsan")) # 右对齐
    print('{:<30}'.format("zhangsan")) # 左对齐
    30:字段长度(最左到最右之间的长度)

    结果显示

     

    精度控制  :.nf

    1. 

    print('{:.2f}'.format(3.14159))
    结果:3.14
    保留两位小数,两位后四舍五入

    2. 

    print('{:.5f}'.format(3.14))
    结果:3.14000
    保留5位小数,不足补0.
    进制转化,b o d x 分别表示二、八、十、十六进制
    
    print('{:b}'.format(20))
    print('{:o}'.format(20))
    print('{:d}'.format(20))
    print('{:x}'.format(20))

    结果:

    10100
    24
    20
    14 


     千位分隔符::,

    print('{:,}'.format(100000000))
    print('{:,}'.format(123456.123456))

    结果:

    100,000,000
    123,456.123456

    展开全文
  • 回调函数

    千次阅读 多人点赞 2019-09-09 17:36:28
    回调函数不是由该函数的实现方直接调用,而是特定的事件或条件发生时由另外的一方调用的,用于对该事件或条件进行响应。 其实回调就是一种利用函数指针进行函数调用的过程. 为什么要用回调呢?比如我要写一个子...

    回调函数就是一个通过函数指针调用的函数。如果你把函数的指针(地址)作为参数传递给另一个函数,当这个指针被用来调用其所指向的函数时,我们就说这是回调函数。回调函数不是由该函数的实现方直接调用,而是在特定的事件或条件发生时由另外的一方调用的,用于对该事件或条件进行响应。

    其实回调就是一种利用函数指针进行函数调用的过程.

    为什么要用回调呢?比如我要写一个子模块给你用,来接收远程socket发来的命令.当我接收到命令后,需要调用你的主模块的函数, 来进行相应的处理.但是我不知道你要用哪个函数来处理这个命令,我也不知道你的主模块是什么.cpp或者.h,或者说,我根本不用关心你在主模块里怎么处理它,也不应该关心用什么函数处理它......怎么办呢?使用回调!

    —— lone wolf

    使用回调函数实际上就是在调用某个函数(通常是API函数)时,将自己的一个函数(这个函数为回调函数)的地址作为参数传递给那个函数。而那个函数在需要的时候,利用传递的地址调用回调函数,这时你可以利用这个机会在回调函数中处理消息或完成一定的操作。

    —— 某专家

    回调函数,就是由你自己写的。你需要调用另外一个函数,而这个函数的其中一个参数,就是你的这个回调函数名。这样,系统在必要的时候,就会调用你写的回调函数,这样你就可以在回调函数里完成你要做的事。

    —— 绿叶

    回调函数是应用程序提供给Windows系统DLL或其它DLL调用的函数,一般用于截获消息、获取系统信息或处理异步事件。应用程序把回调函数的地址指针告诉DLL,而DLL在适当的时候会调用该函数。回调函数必须遵守事先规定好的参数格式和传递方式,否则DLL一调用它就会引起程序或系统的崩溃。通常情况下,回调函数采用标准WindowsAPI的调用方式,即__stdcall,当然,DLL编制者可以自己定义调用方式,但客户程序也必须遵守相同的规定。在__stdcall方式下,函数的参数按从右到左的顺序压入堆栈,除了明确指明是指针或引用外,参数都按值传递,函数返回之前自己负责把参数从堆栈中弹出。

    —— jufengfeng

    看了这么多的资料,我只将每位的定义总结一下就一句话:使用回调函数实际上就是在调用某个函数(通常是API函数)时,将自己写的一个函数(这个函数就是回调函数)的地址作为参数传递给那个函数。回调其实就是提供使用某模块的一种方法。回调函数就好比是一个中断处理函数。

     

    3. 回调函数的作用?应该在什么情况下使用?

    用过STL的人都知道,在STL中众多算法和程序都用到回调函数,这实现了一种策略。只要任何符合我的标准的函数和计算都可以用我这个公式。你可以实现各种各样的回调函数,只要符合我的格式就能用。就上面的程序来说,你只要函数格式符合cllback第二个参数的格式不论你给别人做饭、铺床叠被都可以正常工作。这就是回调的作用,把回调实现留给别人。这是一个用法。
    有一位朋友用分层的概念来解释了回调机制:callback函数为B层,main函数和print函数为A层,A层调用了B层的回调函数callmeback,而B层的回调函数调用了A层的实现函数print。说白了B层就是一个接口。

    有一位朋友用分层的概念来解释了回调机制:callback函数为B层,main函数和print函数为A层,A层调用了B层的回调函数callmeback,而B层的回调函数调用了A层的实现函数print。说白了B层就是一个接口。
    最后要注意的是:回调函数要么是全局函数,要么是静态函数!

    
    #include <stdio.h>
    //回调函数
    int ADD(int (*callback)(int,int), int a, int b){
    	return (*callback)(a,b);//此处回调add函数...
    }
    //普通函数
    int add(int a, int b){
    	return a + b;
    }
     
    int main(void){
    	printf("%d\n",add(1,2));
    	printf("%d\n",ADD(add,1,2));
    	return 0;
    }

     

    C回调函数

    C++回调函数扩展自C回调函数,要想理解C++回调函数,先要理解C回调函数。我们通过一个实例来讲解C回调函数的使用方法。

    //callbackTest.c
    //1.定义函数onHeight(回调函数)
    //@onHeight 函数名
    //@height   参数
    //@contex   上下文
    void onHeight(double height, void* contex)
    {
    	sprint("current height is %lf",height);
    }
    
    //2.定义onHeight函数的原型
    //@CallbackFun 指向函数的指针类型
    //@height      回调参数,当有多个参数时,可以定义一个结构体
    //@contex      回调上下文,在C中一般传入nullptr,在C++中可传入对象指针
    typedef void (*CallbackFun)(double height, void* contex);
    
    //3.定义注册回调函数
    //@registHeightCallback 注册函数名
    //@callback             回调函数原型
    //@contex               回调上下文
    void registHeightCallback(CallbackFun callback, void* contex)
    {
    	double h=100;
    	callback(h,nullptr);
    }
    
    //4.main函数
    void main()
    {
    	//注册onHeight函数,即通过registHeightCallback的参数将onHeight函数指针
    	//传入给registHeightCallback函数,在registHeightCallback函数中调用
    	//callback就相当于调用onHeight函数。
    	registHeightCallback(onHeight,nullptr);
    }

    程序的运行结果是:
    current height is 100
    很多时候,注册的时候并不调用回调函数,而是在其他函数中调用,那我们可以定义一个CallbackFun全局指针变量,在注册的时候将函数指针赋给它,在要调用的调用它。如

    //定义全局指针变量
    CallbackFun* m_pCallback;
    //定义注册回调函数
    void registHeightCallback(CallbackFun callback, void* contex)
    {
    	m_pCallback = callback;
    }
    //定义调用函数
    void printHeightFun(double height)
    {
    	m_pCallback(height,nullptr);
    }
    //main函数
    void main()
    {
    	//注册回调函数onHeight
    	registHeightCallback(onHeight,nullptr);
    	//打印height
    	double h=99;
    	printHeightFun(99);
    }

     程序的运行结果是:
    current height is 99

    C++回调函数

    C++回调函数扩展自C,与C略有不同的是,C++可以使用全局函数和静态函数作为回调函数。考虑到全局函数会破坏封装性,所以一般都用静态成员函数。故除了理解函数指针,还要理解静态成员函数,具体一点是在静态成员函数中访问非静态成员函数的方法,因为我们很可能需要获取静态成员函数中的数据。

    使用场景描述

    比如说你使用了别人提供的sdk,这个sdk可能来自供应商,也有可能来自你的同事,他就提供给你一个注册回调函接口,比如就下面这个,你可以通过回调函数获取到height(某种传感器的实时返回的数据),你要怎么做?

    C++回调函数定义

    //CallbackFun类型
    //@CallbackFun 指向函数的指针类型
    //@height      回调参数,当有多个参数时,可以定义一个结构体
    //@contex      回调上下文,在C中一般传入nullptr,在C++中可传入对象指针
    typedef void (*CallbackFun)(double height, void* contex);
    
    //注册回调函数接口
    //@registHeightCallback 注册函数名
    //@callback             回调函数原型
    //@contex               回调上下文
    void registHeightCallback(CallbackFun callback, void* contex)

    首先,你要定义一个静态成员函数并注册。

    //sensorTest.cpp
    //接收数据类class Sensor
    class Sensor{
    public:
    	Sensor(){}
    	~Sensor(){}
    	//定义回调函数onHeight
    	static void onHeight(double height, void* contex)
    	{
    		cout << "current height is  " << height << endl;
    	}
    	//定义注册回调函数
    	void registCallback()
    	{
    		registHeightCallback(onHeight, this);
    	}
    }
    
    //main 函数
    void main()
    {
    	Sensor sens;
    	sens.registCallback();
    }

    运行程序,我们发现控制台一直在打印
    current height is **
    说明我们的回调函数正确实现了。到这一步不难,只要掌握基本的回调函数概念都能实现。
    现在我们有这样一种情况,我们有另外一个类,要在这个类里面实时打印获取的数据,要怎么做呢?

    静态成员函数访问非静态成员函数的方法

    我们知道静态成员函数中是只能出现静态变量和静态函数的,但是有些时候真的需要访问非静态成员函数或变量,比如我上面说的那种情况。让我们先来实现对同一个类中的非静态成员函数的访问。
    修改class Sensor如下

    //接收数据类class Sensor
    class Sensor{
    public:
    	Sensor(){}
    	~Sensor(){}
    	//定义回调函数onHeight
    	static void onHeight(double height, void* contex)
    	{
    		//cout << "current height is  " << height << endl;
    		Sensor* sen = (Sensor*)contex;
    		if(sen)  //注意判断sen是否有效
    			sen->getHeight(height);
    	}
    	//定义注册回调函数
    	void registCallback()
    	{
    		registHeightCallback(onHeight, this);
    	}
    	//新增的成员函数
    	void getHeight(double height)
    	{
    		cout << "current height is  " << height << endl;
    	}
    }

    如此修改之后,得到与修改前一样的效果(实时打印height),关键点在于注册回调函数的时候将Sensor对象的指针传给了contex,在回调函数中又将contex转换为Sensor对象指针,所以能调用普通函数。
    同理,如果注册时传入某一个对象的指针,就可以在回调函数中对该对象进行操作,这就是我们可以在一个对象中回调另一个对象的思想。

    回调对象

    现在开始解决之前提出的问题,本质是不变的,回调是指针传递,可以是函数指针,也可以是对象指针。

    //先定义一个类class DataPrint
    //打印数据类class DataPrint
    class DataPrint{
    public:
    	DataPrint(){}
    	~DataPrint(){}
    	void printHeight(double height)
    	{
    		cout << "print height is " << height << endl;
    	}
    }
    
    //要在类Sensor中增加DataPrint的指针和一个DataPrint指针赋值函数,class Sensor修改为
    //接收数据类class Sensor
    class Sensor{
    public:
    	Sensor(){}
    	~Sensor(){}
    	//定义回调函数onHeight
    	static void onHeight(double height, void* contex)
    	{
    		DataPrint* dp = (DataPrint*)contex;
    		if(dp)  //注意判断dp是否有效
    			dp->printHeight(height);
    	}
    	//定义注册回调函数
    	void registCallback()
    	{
    		registHeightCallback(onHeight, m_pDataPrint );
    	}
    	//新增的成员函数
    	void getHeight(double height)
    	{
    		//cout << "current height is  " << height << endl;
    	}
    	void setDataPrint(DataPrint* dp)
    	{
    		m_pDataPrint = dp;
    	}
    private:
    	DataPrint* m_pDataPrint;
    }
    
    //main主函数
    void main()
    {
    	DataPrint* dp=new DataPrint();
    	Sensor* sens=new Sensor();
    	//注意这两句的顺序不能颠倒
    	sens->setDataPrint(dp);
    	sens->registCallback();
    }

     这样就能实现在另一个类中取得回调函数的数据,如果无法保证DataPrint的实例化一定在Sensor之前,我们可以这样做

    //先定义一个类class DataPrint
    //打印数据类class DataPrint
    class DataPrint{
    public:
    	DataPrint(){}
    	~DataPrint(){}
    	void printHeight(double height)
    	{
    		cout << "print height is " << height << endl;
    	}
    }
    
    //要在类Sensor中增加DataPrint的指针和一个DataPrint指针赋值函数,class Sensor修改为
    //接收数据类class Sensor
    class Sensor{
    public:
    	Sensor(){}
    	~Sensor(){}
    	//定义回调函数onHeight
    	static void onHeight(double height, void* contex)
    	{
    		Sensor* sen= (Sensor*)contex;
    		if(sen)  //注意判断sen是否有效
    			sen->getHeight(height);
    	}
    	//定义注册回调函数
    	void registCallback()
    	{
    		registHeightCallback(onHeight, m_pDataPrint );
    	}
    	//新增的成员函数
    	void getHeight(double height)
    	{
    		if(m_pDataPrint )
    			m_pDataPrint ->printHeight(height);
    	}
    	void setDataPrint(DataPrint* dp)
    	{
    		m_pDataPrint = dp;
    	}
    private:
    	DataPrint* m_pDataPrint;
    }
    
    //main主函数
    void main()
    {
    	DataPrint* dp=new DataPrint();
    	Sensor* sens=new Sensor();
    	//注意这两句的顺序可以颠倒
    	sens->setDataPrint(dp);
    	sens->registCallback();
    }

    两个的区别是一个直接注册指定类的对象指针,另一个注册当前类的对象指针,间接调用另一个类的对象指针。

    更复杂的讨论

    刚才讨论的问题稍微复杂一点了,不过应该也容易理解,但是我们在实际项目中遇到的情况可能比这个复杂。比如在有层次的软件工程中,回调函数在底层,显示数据的类在上层,我们要如何把底层的数据显示到上层去?容易想到的是上层调用底层,如开个timer刷新,但这是不对的,你无法做到实时调用,你需要的是一个异步的机制,即底层一发生上层就能接收到。
    怎么做呢?还是一样的道理,把上层的类的对象指针传给底层,这时底层需要包含上层的头文件,但这是不对的,上层已经包含了底层的头文件,它们不能互相包含,如何解决这个问题?那就要用到C++继承的特性,首先在底层定义一个基类,然后在上层继承它,在上层实例化这个继承类后,将其指针设置给底层,底层对该指针的操作就是对继承类对象的操作,以此实现数据的传递。

    参考:

    [1] https://www.jianshu.com/p/26784d962f58

    [2] https://blog.csdn.net/weixin_40237626/article/details/82801409

    [3] https://blog.csdn.net/sinat_38183777/article/details/83958887

    [4] https://blog.csdn.net/yidu_fanchen/article/details/80513359

    展开全文
  • 函数 2 之虚函数定义

    千次阅读 2019-01-24 23:20:34
    1、虚函数定义 ...虚函数定义基类中进行的,它是基类中那些需要定义为虚函数的成员函数的声明中冠以关键字 virtual 。定义函数的方法如下: virtual 函数类型 函数名(形参表){ ...

    1、虚函数的定义

    • 虚函数就是在基类中被关键字 virtual 说明,并在派生类中重新定义的函数。
    • 虚函数的作用是允许在派生类中重新定义与基类同名的函数,并且可以通过基类指针或引用来访问基类和派生类中的同名函数。
    • 虚函数的定义是在基类中进行的,它是在基类中在那些需要定义为虚函数的成员函数的声明中冠以关键字 virtual 。定义虚函数的方法如下:
    virtual 函数类型 函数名(形参表){
    	      函数体;
    }
    

      在基类中的某个成员函数被声明为虚函数后,此虚函数就可以在一个或多个派生类中被重新定义。在派生类中重新定义时,其函数原型,包括函数类型、函数名、参数个数、参数类型的顺序,都必须与基类中的原型完全相同。

    例 1:虚函数的使用

    #include<iostream>
    using namespace std;
    class B0{
    	public:
    		virtual void print(char *p){	//定义虚函数 print 
    			cout<<p<<"print()"<<endl;
    		}
    };
    class B1:public B0{
    	public:
    		virtual void print(char *p){	//重新定义虚函数 print 
    			cout<<p<<"print()"<<endl;
    		}
    };
    class B2:public B1{
    	public:
    		virtual void print(char *p){	//重新定义虚函数 print 
    			cout<<p<<"print()"<<endl;
    		}
    };
    int main(){
    	B0 ob0,*op;	//定义基类对象 ob0 和对象指针 op
    	op=&ob0; 
    	op->print("B0::");    //调用基类 B0 的 print 
    	B1 ob1;  //定义派生类 B1 的对象 
    	op=&ob1;
    	op->print("B1::");  //调用派生类 B1 的 print 
    	B2 ob2;
    	op=&ob2;
    	op->print("B2::");
    	return 0;
    }
    

    执行结果:
    在这里插入图片描述
    说明:
    (1)若在基类中,只声明虚函数原型(需加上 virtual),而在类外定义虚函数时,则不必再加 virtual。例如:

    class B0{
    	public:
    			virtual void print(char *p);     //声明虚函数原型,需加上 virtual
    };
    

    在类外,定义虚函数时,不要加 virtual:

    void B0::print(char *p){
    		cout<<p<<"print()"<<endl;
    }
    

    (2)在派生类中,虚函数被重新定义时,其函数的原型与基类中的函数原型(即包括函数类型、函数名、参数个数、参数类型的顺序)都必须完全相同。
    (3)C++ 规定,当一个成员函数被定义为虚函数后,其派生类中符合重新定义虚函数要求的同名函数都自动称为虚函数。因此,在派生类中重新定义该虚函数时,关键字 virtual 可以不写。 但是,为了使程序更加清晰最好在每一层派生类中定义该函数时都加上关键字 virtual。
    (4)如果在派生类中没有对基类的虚函数重新定义,则公有派生类继承其直接基类的虚函数。一个虚函数无论被公有继承多少次,它仍然保持其虚函数的特性。 例如:

    class B0{
    	···
    	public:
    		virtual void show();	//在基类定义 show 为虚函数
    };
    class B1:public B0{
    	···
    };
    

    若在公有派生类 B1 中没有重新定义虚函数 show ,则函数 show 在派生类中被继承,仍是虚函数。
    (5)虚函数必须是其所在类的成员函数,而不能是友元函数,也不能是静态成员函数,因为虚函数调用要靠特定的对象来决定该激活哪个函数。
    (6)使用对象名和点运算符的方式调用虚函数是在编译时进行的,是静态联编,没有利用虚函数的特性。只有通过基类指针访问虚函数时才能获得运行时的多态性。

    例 2:使用对象名和点运算符的方式调用虚函数

    #include<iostream>
    using namespace std;
    class B0{
    	public:
    	   virtual void print(char *p){	//定义虚函数 print 
    			cout<<p<<"print()"<<endl;
    		}
    };
    class B1:public B0{
    	public:
    	  virtual void print(char *p){
    			cout<<p<<"print()"<<endl;
    		}
    };
    class B2:public B1{
    	public:
    	  virtual void print(char *p){
    			cout<<p<<"print()"<<endl;
    		}	
    };
    int main(){
    	B0 ob0;
    	ob0.print("B0::");
    	B1 ob1;
    	ob1.print("B1::");
    	B2 ob2;
    	ob2.print("B2::");
    	return 0;
    }
    

    2、虚析构函数

      在 C++ 中,不能声明虚构造函数,但是可以声明虚析构函数。
      https://blog.csdn.net/aaqian1/article/details/84915540 中介绍了先执行派生类的析构函数,再执行基类的析构函数。

    例 3:虚析构函数的引例 1:

    #include<iostream>
    using namespace std;
    class B{
    	public:
    		~B(){
    			cout<<"调用基类 B 的析构函数\n";
    		}
    };
    class D:public B{
    	public:
    		~D(){
    			cout<<"调用派生类 D 的析构函数\n";
    		}
    };
    int main(){
    	D obj;
    	return 0;
    }
    

      本程序运行结果符合预想,即先执行派生类的析构函数,再执行基类的析构函数。但是,如果在主函数中用 new 运算符建立一个派生类的无名对象和定义了一个基类的对象指针,并将无名对象的地址赋给这个对象指针。当用 delete 运算符撤销无名对象时,系统只执行基类的析构函数,而不执行派生类的析构函数。

    例 4:虚析构函数的引例2

    #include<iostream>
    using namespace std;
    class B{
    	public:
    		~B(){
    			cout<<"调用基类 B 的析构函数\n";
    		}
    };
    class D:public B{
    	public:
    		~D(){
    			cout<<"调用派生类 D 的析构函数\n";
    		}
    };
    int main(){
    	B *p;	//定义指向基类 B 的指针变量 p
    	p=new D;	
    //用运算符 new 为派生类的无名对象动态地分配了一个存储空间,并将地址赋给对象指针 p
    	delete p;
    //用 delete 撤销无名对象,释放动态存储空间
    	return 0; 
    }
    

    执行结果:
    在这里插入图片描述
      当撤销指针 P 所指的派生类的无名对象,而调用析构函数时,采用了静态联编方式,只调用了基类 B 的析构函数。
      如果希望程序执行动态联编方式,在用 delete 运算符撤销派生类的无名对象时,先调用派生类的析构函数,再调用基类的析构函数,可以将基类的析构函数声明为虚析构函数。

    例 5:虚析构函数的使用

    #include<iostream>
    using namespace std;
    class B{
    	public:
    		virtual ~B(){
    			cout<<"调用基类 B 的析构函数\n";
    		}
    };
    class D:public B{
    	public:
    		virtual ~D(){
    			cout<<"调用派生类 D 的析构函数\n";
    		}
    };
    int main(){
    	B *p;	//定义指向基类 B 的指针变量 p
    	p=new D;	
    //用运算符 new 为派生类的无名对象动态地分配了一个存储空间,并将地址赋给对象指针 p
    	delete p;
    //用 delete 撤销无名对象,释放动态存储空间
    	return 0; 
    }
    
    

    在这里插入图片描述  由于使用了虚析构函数,程序执行了动态联编,实现了运行的动态性。虽然派生类的析构函数与基类的析构函数名字不相同,但是如果将基类的析构函数定义为虚函数,由该基类所派生的所有派生类的析构函数也都自动成为虚函数。

    3、虚函数与重载函数的关系

      在一个派生类中重新定义基类的虚函数是函数重载的另一种形式,但它不同于一般的函数重载。
      当普通的函数重载时,其函数的 参数参数类型 有所不同,函数的 返回类型 也可以不同。但是,当重载一个虚函数时,即在派生类中重新定义虚函数时,要求函数名、返回类型、参数个数、参数的类型和顺序与基类中的虚函数原型完全相同。①如果仅仅返回类型不同,其余均相同,系统会给出错误信息;②若仅仅函数名相同,而参数的个数,类型或顺序不同,系统将它作为普通的函数重载,这时虚函数的特性将丢失。

    例 6:虚函数与重载函数的关系

    #include<iostream>
    using namespace std;
    class Base{
    	public:
    		virtual void fun1();
    		virtual void fun2();
    		virtual void fun3();
    		void fun4();
    };
    class Derived:public Base{
    	public:
    	    virtual void fun1();	//fun1 是虚函数,这里可不写 virtual 
    		void fun2(int x);		//与基类中的 fun2 作为普通函数重载,虚特性消失
    	//	char fun3();			//错误,因为与基类只有返回类型不同,应删去
    		void fun4(); 
    };
    void Base::fun1(){
    	cout<<"---Base fun1---"<<endl;	
    }
    void Base::fun2(){
    	cout<<"---Base fun2---"<<endl;	
    }
    void Base::fun3(){
    	cout<<"---Base fun3---"<<endl;	
    }
    void Base::fun4(){
    	cout<<"---Base fun4---"<<endl;	
    }
    void Derived::fun1(){
    	cout<<"---Derived fun1---"<<endl;
    } 
    void Derived::fun2(int x){
    	cout<<"---Derived fun2---"<<endl;
    }
    /*
    void Derived::fun3(){
    	cout<<"---Derived fun3---"<<endl;
    }*/
    void Derived::fun4(){
    	cout<<"---Derived fun4---"<<endl;
    }
    int main(){
    	Base d1,*bp;
    	Derived d2;
    	bp=&d2;
    	bp->fun1();
    	bp->fun2();
    	bp->fun4();
    	return 0;
    }
    

    执行结果:
    在这里插入图片描述

    4、多重继承与虚函数

      多重继承可以视为多个单继承的组合。因此,多重继承情况下的虚函数调用与单继承情况下的虚函数调用有相似之处。

    例 7:多重继承与虚函数的例子

    #include<iostream>
    using namespace std;
    class Base1{
    	public:
    		virtual void fun(){		//定义 fun 是虚函数 
    			cout<<"--Base1--\n";
    		}
    };
    class Base2{
    	public:
    		void fun(){		//定义 fun 是普通的成员函数 
    			cout<<"--Base2--\n";
    		}
    };
    class Derived:public Base1,public Base2{
    	public:
    		void fun(){
    			cout<<"--Derived--\n";
    		} 
    };
    int main(){
    	Base1 *ptr1;	//定义指向基类 Base1 的对象指针 ptr1
    	Base2 *ptr2;	//定义指向基类 Base2 的对象指针 ptr2
    	Derived obj3;	//定义派生类 Derived 的对象 obj3 
    	ptr1=&obj3;		
    	ptr1->fun();	
    //此处的 fun为虚函数,因此调用派生类 Derived 的虚函数 fun
    	ptr2=&obj3;
    	ptr2->fun();	
    //此处的 fun为非虚函数,而 ptr2 为类 Base2 的对象指针,因此调用基类 Base2 的函数 fun
    	return 0;
    }
    

    执行结果:
    在这里插入图片描述  相对于 Base1 的派生路径,由于 Base1 中的 fun 是虚函数,当声明为指向 Base1 的指针指向派生类 Derived 的对象 obj3 时,函数 fun 呈现出虚特性。
      相对于 Base2 的派生路径,由于 Base2 中的 fun 是
    一般成员函数,所以此时它只能是一个普通的重载函数,当声明为指向 Base2 的指针指向 Derived 的对象 obj3 时,函数 fun 只呈现普通函数的重载特性。

    5、虚函数举例

    例 8:应用 C++ 的多态性,计算三角形、矩形和圆的面积。

    #include<iostream>
    using namespace std;
    class Figure{	//定义一个公共基类 
    	protected:
    		double x,y;
    	public:
    		Figure(double a,double b){
    			x=a;
    			y=b;
    		}
    		virtual void area(){	//定义一个虚函数,作为界面接口 
    			cout<<"在基类中定义的虚函数,";
    			cout<<"为派生类提供一个公共接口,";
    			cout<<"以便派生类根据需要重新定义虚函数。";
    		}
    };
    class Triangle:public Figure{	//定义三角形派生类 
    	public:
    		Triangle(double a,double b):Figure(a,b){ 	//构造函数 
    		}
    		void area(){	//虚函数重新定义,用作求三角形的面积 
    			cout<<"三角形的高是:"<<x<<",底是:"<<y;
    			cout<<",面积是:"<<0.5*x*y<<endl;
    		}
    };
    class Square:public Figure{
    	public:
    		Square(double a,double b):Figure(a,b){
    		}
    		void area(){	//虚函数重新定义,用作求矩形的面积 
    			cout<<"矩形的长是:"<<x<<",宽是:"<<y<<",面积是:"<<x*y<<endl; 
    		}
    };
    class Circle:public Figure{		//定义圆派生类
     	public:
     		Circle(double a):Figure(a,a){
    		 }
    		 void area(){
    		 	cout<<"圆的半径是:"<<x<<",面积是:"<<3.1416*x*x<<endl;
    		 }
    };
    int main(){
    	Figure *p;
    	Triangle t(10.0,6.0);
    	Square s(10.0,6.0);
    	Circle c(10.0);
    	p=&t;
    	p->area();
    	p=&s;
    	p->area();
    	p=&c;
    	p->area();
    	return 0;
    }
    

    运行结果:
    在这里插入图片描述

    展开全文
  • 7-6 计算符号函数的值 (10 分)

    千次阅读 2019-09-25 21:53:32
    对于任一整数n,符号函数sign(n)的定义如下: 请编写程序计算该函数对任一输入整数的值。 输入格式: 输入一行中给出整数n。 输出格式: 一行中按照格式“sign(n) = 函数值”输出该整数n对应的函数值。 输入样例1...

    7-6 计算符号函数的值 (10 分)
    对于任一整数n,符号函数sign(n)的定义如下:

    在这里插入图片描述

    请编写程序计算该函数对任一输入整数的值。

    输入格式:
    输入在一行中给出整数n。

    输出格式:
    在一行中按照格式“sign(n) = 函数值”输出该整数n对应的函数值。

    输入样例1:
    10
    输出样例1:
    sign(10) = 1
    输入样例2:
    0
    输出样例2:
    sign(0) = 0
    输入样例3:
    -98
    输出样例3:
    sign(-98) = -1

    #include<stdio.h>
    int main(int argc,char* argv[])
    {
    	int n;
    	int result;
    	scanf("%d",&n);
    	if(n<0)
    	result=-1;
    	else if(n==0)
    	result=0;
    	else
    	result=1;
    	printf("sign(%d) = %d",n,result);
    	return 0;
    }
    
    展开全文
  • 如何Python中定义函数及实例

    千次阅读 2020-04-20 15:35:39
    使用函数时需要先调用,才可以使用。 def hello(): # 函数定义 print('hello1') print('hello2') print('hello3') hello() # 函数的调用,直接输函数名 def add(): num1 = 20 num2...
  • VBA函数定义及说明

    千次阅读 2020-06-24 11:18:28
    函数定义函数返回对象,默认参数,不定长参数
  • 内联函数和宏定义函数的区别

    千次阅读 2019-05-17 19:53:55
    内联函数编译时展开,而宏预编译时展开;编译的时候,内联函数直接被嵌入到目标代码中去,而宏只是一个简单的文本替换。 内联函数可以进行诸如类型安全检查、语句是否正确等编译功能,宏不具有这样的功能;...
  • matlab定义数组和相关函数

    万次阅读 2019-11-04 19:44:50
    matlab中对数组的定义较为灵活,因为特殊矩阵较多,所以有许多特定的定义方法。比较常见的有三种: 普通数组定义:用和C语言类似的定义方法,用分号隔开每行数据。 全零数组定义:zeros(x,y),x代表行数,y...
  • 函数中的声明和变量的定义

    千次阅读 2019-04-14 19:44:13
    某些编程语言里,函数声明和函数定义区分开的,一个函数声明包括提供对函数名,参数的名字(传统还有参数的类型),但不必给出函数的任何代码,具体的代码通常属于函数定义的范畴。 ​ 声明和定义有区别的...
  • Java函数式编程详解

    万次阅读 多人点赞 2019-05-05 21:46:49
    函数式编程的优点提高编码的效率,增强代码的可读性。本文历时两个多月一点点写出来,即作为心得,亦作为交流。 1.Java函数式编程的语法: 使用Consumer作为示例,它是一个函数式接口,包含一个抽象方法accept,...
  • python中函数定义以及如何编写一个函数

    万次阅读 多人点赞 2019-06-30 18:06:52
    1.函数定义 函数是组织好的,可重复使用的,用来实现单一,或相关联功能的代码段 函数能提高应用的模块性,和代码的重复利用率 Python提供了许多内建函数,比如print()。但你也可以自己创建函数,这被叫做用户...
  • 使用 typedef 定义函数指针,更优雅的使用函数指针

    万次阅读 多人点赞 2018-08-24 09:23:56
    简介 关于函数指针的介绍,这里就不做过多说明了,不了解的同学可以...使用 typedef 定义函数指针 通过下面这个例子,我们看看 typedef 是怎么搭配函数指针使用的吧。 int add(int a, int b) { return a + b; ...
  • python def 定义函数,调用函数

    万次阅读 2019-07-13 22:04:09
    python def 定义函数,调用函数 def sum_2_nums(a,b): #def 定义函数 result = a+b print('%d+%d=%d'%(a,b,result)) num1 = int(input('请输入第一个数字:')) num2 = int(input('请输入第二个数字:')) sum_2_...
  • 高数——多元函数定义及极限

    千次阅读 2019-10-21 10:51:33
    之前我们学习的导数、微分和积分都是针对一元函数的,也就是函数只依赖一个变量,但是我们今后遇到的实际...和一元函数一样,二元函数也是有定义域和值域的,一元函数定义域是 轴一个“线段”的点的集合,而...
  • 类外定义成员函数 成员函数可以类体中直接定义。也可以类体中只写成员函数的声明,而类的外面进行函数定义。如: class Student { public : void display( ); //公用成员函数原型声明 private : int ...
  • C 函数定义与调用及例题

    千次阅读 2019-02-12 16:36:40
    · C语言中,函数(Function)是一个处理过程,即一段程序的工作放在函数中进行,函数结束时可以携带或不带处理结果。 · C语言程序处理过程全部都是以函数形式出现,最简单的程序至少也有一个main函数。 ·从...
  • C语言函数嵌套定义问题

    万次阅读 2017-03-04 21:52:37
    实际函数能否嵌套定义与编译器有关,GCC编译器下嵌套定义没问题,可以正常运行,我code blocks 和 Dev C++两个IDE(两者都用GCC)下测试了如下两个程序,都没问题: 1.main函数中的嵌套定义。 #include...
  • C语言函数定义和声明

    万次阅读 多人点赞 2019-08-08 14:38:17
    本科学C语言的时候,就...1.C语言中,函数定义顺序是有讲究的:默认情况下,只有后面定义函数才可以调用前面定义过的函数 1 int sum(int a, int b) { 2 return a + b; 3 } 4 5 int main() 6 { 7 int c = ...
  • 数组的定义main函数外面

    千次阅读 2018-08-04 16:34:12
    //输出一个整数序列中与指定数字相同的数的... scanf("%d ",&a[i]);  }    scanf("%d",&b);    for(int j=0;j;j++)  {  if(a[j]==b)  k++;  }     printf("%d",k);    return 0;   }
  • linux shell 可以用户定义函数,然后shell脚本中可以随便调用。Shell 函数定义的语法格式如下: [function] funname [()]{ 函数体 [return int;] } 格式1: 简化写法,不写 function 关键字: 函数名(){ ...
  • python中函数定义和调用注意事项

    千次阅读 2018-08-10 16:37:27
    1.函数定义注意事项 2.函数调用的注意事项 3.函数参数传递的本质 4.匿名的函数lambda的使用 5.return语句的使用注意事项 1.函数定义注意事项 1.函数的格式: def 函数名(参数): #注意函数以冒号开始 ...
  • sort函数用法

    万次阅读 多人点赞 2018-04-10 09:30:54
    sort函数是一个非常强大的排序函数用法如下://使用sort函数进行升序排序#include &lt;stdio.h&gt;#include &lt;algorithm&gt;//sort函数所在的函数库using namespace std;//sort所在的标准命名空间...
  • 函数 def定义函数

    千次阅读 2019-04-07 22:21:33
    函数 def定义函数 必须参数 不定长参数:def add(*args) add(1,2,3,4,5)无命名参数 元组 def add(**args)print_info ('wenson',30,‘male’)把键值对入到字典里储存 关于不定长参数的位置:*args放在左边,...
  • C++ 类(构造函数和析构函数)

    万次阅读 多人点赞 2018-07-20 19:00:51
    文章概述 构造函数和析构函数的由来?...类的数据成员不能类的声明时候初始化,为了解决这个问题? 使用构造函数处理对对象的初始化。构造函数是一种特殊的成员函数,与其他函数不同,不需要用户调用它,而...
  • 【STM32】HAL库 STM32CubeMX教程四---UART串口通信详解

    万次阅读 多人点赞 2019-08-11 08:57:51
    今天我们学习STM32CubeMX串口的操作,以及HAL库串口的配置,我们会详细的讲解各个模块的使用和具体功能,并且基于HAL库实现Printf函数功能重定向,UART中断接收,本系列教程将HAL库与STM32CubeMX结合一起讲解,使...
  • 关于C++模板函数声明与定义的问题

    万次阅读 多人点赞 2018-07-22 21:59:37
    关于C++模板函数声明与定义的问题 ...今天写代码的时候,发现了一个关于模板函数的问题。如下所示, demo.h代码 #ifndef DEMO_H #define DEMO_H class Demo { public: Demo(); virtual ~D...
  • python 函数定义函数

    千次阅读 2018-02-02 16:02:23
    一直不明白这样写具体有什么意义。直到我准备实现一个类似与 java 中的 Timer#schedule...而要实现这种重复定时器,似乎需要使用 “函数定义函数的”的方式才可以。 def scheduler_build(delay, cmd): def b
  • 函数名称作为返回值答案:D答案解析:递归函数是指函数内部包含对本函数的再次调用。2、关于递归函数基例的说明,以下选项中错误的是A.递归函数必须有基例B.递归函数的基例不再进行递归C.每个递归函数都只能有一个基...
  • 就像自定义数据类型一样,我们也可以先定义一个函数指针类型,然后再用这个类型来申明函数指针变量。 我先给你一个自定义数据类型的例子。 typedef int* PINT; //为int* 类型定义了一个PINT的别名 int main
  • C++函数定义与使用

    万次阅读 多人点赞 2018-03-03 23:10:27
    函数定义和使用main就是一个函数,它是C++程序的主函数。一个C++程序可以由一个主函数和若干子函数组成。主函数是程序执行的开始点。由主函数调用子函数,子函数还可以再调用其它子函数。调用其它函数函数称为...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 1,341,384
精华内容 536,553
关键字:

对于定义在d上的函数