精华内容
下载资源
问答
  • N = 1的宇宙膨胀的超重力模型,其膨胀子属于大量矢量多重体,并且膨胀后自然发生SUSY断裂,将其重新定义为无质量矢量超场与希格斯和波洛尼手性超场相互作用的超对称U(1)尺度理论,所有 加上超重力。 U(1)规范...
  • 我们构建了一个关于重夸克自旋和手性对称的一小子交换势,以证明哪些HQS多重体被实现为束缚。 通过求解耦合通道Schrödinger方程,我们研究了具有和的重介子-重子系统。 具有相同LCS结构的结合在重夸克极限处...
  • 性意味着有多重形式。在面向对象编程范式中,多性往往表现为”一个接口,多个功能”。 多性可以是静态的或动态的。在静态多性中,函数的响应是在编译时发生的。在动态多性中,函数的响应是在运行时发生...
  • 虚函数 2 之虚函数的定义

    千次阅读 2019-01-24 23:20:34
    1、虚函数的定义 虚函数就是在基类中被关键字 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;
    }
    

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

    展开全文
  • 量子中的各种“

    千次阅读 2018-10-21 10:33:13
    一般来说,纠缠是与可分离相对的,如果一个多粒子可以写成部分粒子的乘积形式,则这个为可分离,否则即为纠缠(一般书上对纠缠定义)。叠加是与表象的基矢相联系的,如果基矢是完备的,那么便...

    纠缠态VS叠加态

    纠缠态是叠加态的一种特殊的情形,它是由两个或两个以上的粒子构成的一个态,其特征是不能分解成两个态的乘积。单粒子没有纠缠态,但可以有叠加态,这就是纠缠态与叠加态最大的区别。一般来说,纠缠态是与可分离态相对的,如果一个多粒子态可以写成部分粒子态的乘积形式,则这个态为可分离态,否则即为纠缠态(一般书上对纠缠态的定义)。叠加态是与表象的基矢相联系的,如果基矢是完备的,那么态便可以写成这组基矢的叠加形式(即叠加态)。
    从数学角度看,纠缠是指不能因式分解,叠加是指可以因式相加。
    再看两态的起源,叠加态起源于双缝干涉实验,是量子力学五个基本假定之一,也是量子力学最诡秘难理解的地方,大致的意思是物理系统在被测量前可以处于多个状态的叠加,如薛定谔猫(生与死的叠加),惠勒的猫(此与彼的叠加)等等。纠缠态概念是1935年薛定谔提出来的,实际起源于EPR佯谬,大致的意思是两个纠缠在一起的粒子,无论分开多远,对一个粒子的操作会立即影响另外一个粒子。
    除了上述区别之外,两种态之间还是有联系的,纠缠态通过叠加态起作用,正是态的叠加导致纠缠的出现(不知道这样理解是否正解),钽显然的是假如多粒子态之间没有叠加,则系统的态便能写成分离形式,于是纠缠不出现,但是如何从物理意义的角度来理解态的叠加导致纠缠的出现,目前我还没有一个很好的理解。
    持续更新ing…

    reference
    http://blog.sina.com.cn/s/blog_5fb3f1250100g4zo.html

    展开全文
  • java多

    千次阅读 2016-12-03 19:01:01
    性是指同一个名字的若干个方法,有不同的实现(即方法体中的代码不一样)。 多态的两种表现形式:方法重载overloading(静态多性) 方法覆盖overriding (动态多性) 方法的重载在Java中每个方法都有签名,...

    多态性是指同一个名字的若干个方法,有不同的实现(即方法体中的代码不一样)。
    多态的两种表现形式:

    方法重载overloading(静态多态性)
    方法覆盖overriding (动态多态性)
    

    方法的重载

    在Java中每个方法都有签名,就是方法名以及参数的个数和类型。如果两个方法参数的个数或类型不同,它们可以具有相同的名字,这种现象叫做重载。当调用方法时,编译器通过比较自变量参数的个数和类型来查找匹配得最好的方法。
    签名不包括返回类型或者抛出异常的列表,所以不能通过这些来重载方法。
    对于重载的多个同名方法,在编译时能够确定执行同名方法中的哪一个,故也称为编译时多态性。

    代码:

    class Father{
        int x=5;
        int addX(int b){
            return x+b;
        }
    }
    class Son extends Father{
        int addX(int b,int c){
            return x+b+c;
        }   
       String addX(String s){
            return x+s;
        }
    }
    public class Test{
        public static void main(String args[]){
        Son a=new Son();
        System.out.println(a.addX(2));
        System.out.println(a.addX(2,3));
        System.out.println(a.addX("2"));
        }
    }
    
    result:
    
    7
    10
    52
    

    方法的覆盖

    在子类和超类中有同名的方法(参数也相同),子类中的方法覆盖超类的方法。
    如果超类和子类有同名且参数相同的方法,那么超类的对象调用超类的方法,子类的对象调用子类的方法。
    通过覆盖可以使同名的方法在不同层次的类中有不同的实现。

    注意:子类中重写的方法和父类中被重写的方法要具有相同的名字,相同的参数表和相同的返回类型,只是函数体不同。

    Code:

    class Father{
        int x=8;
        int addX(int b){
            return x+b;
        }
    }
    class Son extends Father{
        int addX(int c){
            return x+c+10;
        }
    }
    public class Test{
        public static void main(String args[]){
            Son a=new Son();
            System.out.println(a.addX(2));
        }
    }
    //调用被覆盖的父类方法:
    class Son extends Father{
        int addX(int c){
            return super.addX(c);
        }
    }
    

    方法覆盖的原则

    子类方法的名称、参数签名和返回类型必须与其父类的方法的名称、参数签名和返回类型一致。
    子类方法不能缩小父类方法的访问权限。
    子类方法不能抛出比父类方法更多的异常。
    方法覆盖只存在于子类和父类(包括直接父类和间接父类)之间。在同一个类中方法只能被重载,不能被覆盖。
    父类的静态方法不能被子类覆盖为非静态的方法,反之亦然。
    子类可以定义与父类的静态方法同名的静态方法,以便在子类中隐藏父类的静态方法。
    父类的私有方法不能被覆盖。
    父类的抽象方法可以被子类覆盖:子类实现父类的方法或重新声明父类的抽象方法。
    

    Code:

    class Father{
        int x=8;
        int addX(int b){
            return x+b;
        }
    }
    class Son extends Father{
        @Override
        int addX(int c){
            return x+c+10;
        }
    }
    
    Java注解(annotation),Override确保子类覆盖(重写)超类方法。
    

    动态多态性

    一个特定的变量可以用于引用不同类型的对象,并且自动调用该变量引用的特定类型对象的方法,这样就使得一个方法的调用根据该调用所用到的不同对象类型而响应不同的操作。如果在编译时不能确定,只能在运行时才能确定执行多个同名方法中的哪一个,则称为运行时多态性(动态多态性)。

    Code:

    class Student{
        String name;
        public Student(String n){
            name=n;
        }
        public String toString(){
            return name;
        }
    }
    class Undergraduate extends Student{
        String teacher;
        public Undergraduate(String n,String t){
            super(n);
            teacher=t;
        }
        public String toString(){
                    return name+"的班主任是"+teacher;
        }
    }
    
    class Postgraduate extends Student{
        String director;
        public Postgraduate(String n,String d){
            super(n);
            director=d;
        }
        public String toString(){
                    return name+"的导师是"+director;
        }
    }
    public class Test{
        public static void print(Student s){
           System.out.println ("姓名:"+s.name);
        }
    
        public static void main (String[] args) {
            Student a=new Undergraduate("小张","张老师");
            Student b=new Postgraduate("小王","李教授");
            Undergraduate c=new Undergraduate("小赵","钱老师");
            System.out.println (a.toString());
            System.out.println (b.toString());
            print(c);
        }
    }
    
    result:
    
    小张的班主任是张老师
    小王的导师是李教授
    姓名:小赵
    

    使用多态时必须满足的条件:

    派生类对象的方法调用必须通过一个基类类型的变量进行。
    调用的方法必须在派生类中被定义。
    调用的方法也必须被声明为基类的一个成员。
    基类和派生类中对应的方法的签名必须相同。
    派生类的方法的访问说明符不能比基类有更多的限制。
    

    抽象类

    Abstract关键字可修饰类和方法,被修饰的类称为抽象类,被修饰的方法称为抽象方法。
    抽象类中的方法定义可以没有方法体,只有方法声明。抽象类没有对象,也就是说,一个抽象类不能通过new操作符直接实例化。
    被abstract修饰的方法在非抽象的子类中必须有具体的实现。
    抽象类是专门设计来让子类继承的类。
    抽象类提供一个类型的部分实现,可以有实例变量,构造方法,抽象方法和具体方法。
    抽象类作为系统中多个子类的共同父类,它所体现的是一种模板式设计。
    抽象类作为多个子类的抽象父类,可以被当成系统实现过程中的中间产品,这个中间产品已经实现了系统的部分功能,但这个产品依然不能当成最终产品,必须有更进一步的完善,这种完善可能有几种不同方式。
    
    
    abstract class 类名{  
       成员变量;
       方法( ){ 方法体  };//定义一般方法
       abstract 方法( );    //定义抽象方法
    }
    

    对于成员方法,不能同时用static和abstract说明。对于类,不能同时用final和abstract说明。
    有抽象方法的类一定是抽象类,抽象类不一定有抽象方法。

    代码:

    abstract class Shape{
        protected String name;
    
        public Shape(String name){
            this.name=name;        
        }
    
        abstract protected double getArea();    
    }
    
    class Rectangle extends Shape{
        double width,length;
        public Rectangle(String name, double width, double length){
            super(name);
            this.width=width;
            this.length=length;
        }
    
        public double getArea(){
            return width*length;
        }
    }
    public class Test {
        public static void main(String args[]) {
            Rectangle r=new Rectangle("矩形", 10.0, 23.5);
            System.out.println(r.getArea());
        }
    }
    

    接口

    "接口"是抽象类的概念,实际上是一组相关常量和(或)抽象方法的集合,并且在大多数情况下,它只包含方法。
    接口不会定义方法是什么,而只定义方法的形式,即名称、参数和返回类型,因此接口中的方法都是没有方法体的抽象方法。
    接口中只能定义 static final 域。
    接口定义的仅仅是实现某一特定功能的一组方法的对外接口和规范,而并没有真正地实现这个功能。
    接口的功能实现是在"继承"了这个接口的各个类中完成的,由这些类来具体定义接口中所有抽象方法的方法体。
    通常把对接口的"继承"称为"实现"。
    

    定义接口的格式

    public  interface  接口名  [extends  父接口名列表]  {  
             // 常量域声明
            [public static final]  域类型  域名 = 常量值;
    
               // 抽象方法声明
            [public abstract]  返回值类型  方法名( 参数列表 ) ;
    }
    

    接口的实现

    一个类要实现接口时,要注意下列问题:

    在类的声明部分,用implements关键字声明该类将实现哪些接口。 
    如果实现了某个接口的类不是abstract的抽象类,则在类的定义部分必须实现指定接口的所有抽象方法,即为所有抽象方法定义方法体。
    如果实现了某个接口的类是abstract的抽象类,则它可以不实现指定接口的所有抽象方法。
    接口的抽象方法的访问控制符为public,所以类在实现方法时,必须显式地使用public。
    实现接口的类要实现接口的全部方法。如果不需要某个方法,也要定义成一个空方法体的方法。
            如:public void 方法名()  {  } 
    

    例子:

    interface CalArea {
        double PI = 3.14;
    
        double getArea();
    }
    
    class Circle implements CalArea {
        double r;
    
        public Circle(double r) {
            this.r = r;
        }
    
        public double getArea() {
            // PI=3.14159; 错误,pi隐含为final和static的
            return PI * r * r;
        }
    }
    
    class Square implements CalArea {
        double s;
    
        public Square(double s) {
            this.s = s;
        }
    
        public double getArea() {
            return s * s;
        }
    }
    
    public class Test {
        public static void main(String args[]) {
            Circle a = new Circle(3);
            Square b = new Square(3);
            System.out.println(a.getArea());
            System.out.println(b.getArea());
        }
    }
    

    例子:

    interface Remote {
        void open();
    
        void close();
    }
    
    class Tv implements Remote {
        public void open() {
            System.out.println("打开电视。");
        }
    
        public void close() {
            System.out.println("关闭电视。");
        }
    }
    
    class Vcd implements Remote {
        public void open() {
            System.out.println("打开VCD。");
        }
    
        public void close() {
            System.out.println("关闭VCD。");
        }
    }
    
    public class Test {
        public static void main(String args[]) {
            Remote r = new Tv();
            r.open();
            r.close();
            r = new Vcd();
            r.open();
        }
    }
    

    接口作为系统与外界交互的窗口,体现的是一种规范。
    对接口的实现者而言,接口规定了实现者必须向外提供哪些服务(以方法的形式来提供);
    对于接口的调用者而言,接口规定了调用者可以调用哪些服务,以及如何调用这些服务(就是如何来调用方法)。
    当在一个程序中使用接口时,接口是多个模块间的耦合标准;当在多个应用程序之间使用接口时,接口是多个程序之间的通信标准。

    接口和抽象类的区别

    接口可以多重继承,抽象类不可以。
    抽象类内部可以有实现的方法,接口则没有实现的方法。
    接口与实现它的类不构成类的继承体系,即接口不是类体系的一部分。因此,不相关的类也可以实现相同的接口。而抽象类是属于一个类的继承体系,并且一般位于类体系的顶层。
    接口的优势:通过实现多个接口实现多重继承,能够抽象出不相关类之间的相似性。
    创建类体系的基类时,若不定义任何变量并无需给出任何方法的完整定义,则定义为接口;必须使用方法定义或变量时,考虑用抽象类。

    内部类

    大部分时候,我们把类定义成一个独立的程序单元。在某些情况下,我们把一个类放在另一个类的内部定义,这个定义在其他类内部的类就被称为内部类,包含内部类的类被称为外部类。
    内部类有如下作用:

    ①内部类提供了更好的封装。
    ②内部类方法可以访问外部类私有数据。
    

    内部类的类名只用于定义它的类或语句块之内,在外部引用它时必须给出带有外部类名的完整名称,并且内部类的名字不允许与外部包类的名字相同。
    内部类可以是抽象类或接口,若是接口,则可以由其它内部类实现
    按照内部类是否含有显示的类名,可将内部类分为:

    实名内部类
    局部内部类
    匿名内部类
    

    内部类一般用于定义与其外部的对象有很强关联的对象,并且两者之间通常有紧密的联系。
    当定义内部类的时候,它与其他类成员一样,会成为外部类的一个成员;也可以具有访问属性,并且外部类对它的访问性也是同样取决于这个属性值。

    实名内部类

    格式:
        [类修饰词表] class 类名 [extends 父类名]  [implements 接口名列表]{
            类体
        }
    

    实名内部类的封装性增加了保护模式和私有模式,即实名内部类的修饰词可以是protected或private
    实名内部类的修饰词可以是static,称为静态实名内部类
    没有static修饰的内部类,称为不具有静态属性的实名内部类,它的成员域若有静态属性,则必须有final属性,但不能有静态属性的方法

    代码:

    public class Test {
        JFrame frame=new JFrame("测试窗口"); //窗口
        JPanel panel=new JPanel(); //面板
        private JLabel label=new JLabel("没有操作"); //标签
        private JButton button=new JButton("确定"); //按钮
    
        private class ButtonListerner implements ActionListener{ //监听器类
            @Override
            public void actionPerformed(ActionEvent e) {
                label.setText("点击了按钮");     
            }       
        }
    
        public Test(){
            panel.add(label); //将标签加到面板中
            panel.add(button); //将按钮加到面板中
            frame.add(panel); //将面板加到窗口中        
            button.addActionListener(new ButtonListerner());
    
            frame.setBounds(200, 100, 400, 300);
            frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
            frame.setVisible(true);
        }   
    
        public static void main(String args[]) {        
            new Test();         
        }
    }
    

    局部内部类

    如果把一个内部类放在方法里定义,则这个内部类就是一个局部内部类,局部内部类仅在该方法里有效。

    1、在局部内部类前不能用public、protected和private,只允许是abstract、final或不加。
    2、可以定义与外部类同名的变量。
    3、不可以定义静态变量和方法。
    4、可以访问外部类的局部变量,但是变量必须是final的。
    5、可以访问外部类的所有成员。
    

    代码:

    class Outter {
        String str="abc";
        int a=10;
    
        public void sample1() {
            final int b=12;
            String str3="123";
    
            class Inner { // 不能用public、protected和private修饰类
                int a=12;
    
                // static String str3="aaa"; 内部类中不能定义STATIC变量。
                public void sample2() {
                    System.out.println(b); //局部常量b
                    System.out.println(str); //外部类成员变量str
                    System.out.println(Outter.this.a);//外部类成员变量a
                    System.out.println(a); //内部类成员变量a
                    // 不能引用另一方法中定义的内部类中非终态变量 str3
                    // System.out.println("外部类成员变量str3的值"+str3);
                }
            }
            new Inner().sample2();
        }
    }
    public class Test {
        public static void main(String[] args) {
            Outter outter=new Outter();
             outter.sample1();
        }
    }
    

    匿名类

    有时仅仅为了在程序中定义一个对象而定义类,而且这个对象的唯一作用就是将它作为实参传递给方法。在这种情况下,只要类扩展已存在的类或者实现接口,就可以选择将其作为匿名类。
    匿名类没有名字,类的定义和一个实例的创建同时进行,也就是说定义实际上是写在new的代码中,而不是拥有class关键字;匿名类不能有修饰符,也不能定义构造方法。

    new 父类名(父类型的构造方法的调用参数列表){
        类体
    }
    

    代码1:

    interface A {
        void print();
    }
    
    public class Test {
        public static void main(String args[]) {
            A a=new A() {
                public void print() {
                    System.out.println("匿名类");
                }
            };
    
            a.print();
        }
    }
    
    public class Test {
        JFrame frame=new JFrame("测试窗口"); //窗口
        JPanel panel=new JPanel(); //面板
        private JLabel label=new JLabel("没有操作"); //标签
        private JButton button=new JButton("确定"); //按钮
    
        public Test(){
            panel.add(label); //将标签加到面板中
            panel.add(button); //将按钮加到面板中
            frame.add(panel); //将面板加到窗口中
    
            button.addActionListener(new ActionListener() {         
                @Override
                public void actionPerformed(ActionEvent e) {
                    label.setText("点击了按钮"); 
                }
            });
        }
    }
    

    泛型类

    泛型是JDK5.0后出现的新概念,泛型的本质是参数化类型,也就是所操作的数据类型被指定为一个参数。当这种参数类型用在类中时,该类就被称为泛型类。
    泛型类定义的格式:

    [类修饰符] class类名<类型参数列表> [extends 父类名] [implement 接口名列表]{
          类体
    }
    

    类型参数的定义方式有以下三种*:

    类型变量标识符
    类型变量标识符 extends 父类名
    类型变量标识符 extends 父类名1 & 父类名2 ...
    

    规则和限制:

    泛型的类型参数可以有多个。
    泛型的类型参数只能是类类型(包括自定义类),不能是简单类型。
    在static方法中不可以使用泛型,泛型变量也不可以用static关键字来修饰。
    不可以定义泛型数组。
    

    代码:

    class MyClass<T, U> {
      private T a;
      private U b;
    
      public MyClass(T a, U b) {
        this.a = a;
        this.b = b;
      }
    
      public T getA() {
        return a;
      }
    
      public U getB() {
        return b;
      }
    }
    
    public class Test {
      public static void main(String[] args) {
        MyClass<String, Integer> m = new MyClass<String, Integer>("abc", 123);
        String s = m.getA();
        System.out.println(s);
        Integer i = m.getB();
        System.out.println(i);
      }
    }
    

    而不用泛型的代码:

    class MyClass {
     private Object  a;
     private Object  b;
    
      public MyClass(Object a, Object b) {
        this.a = a;
        this.b = b;
      }
    
      public Object getA() {
        return a;
      }
    
      public Object getB() {
        return b;
      }
    }
    
    public class Test {
      public static void main(String[] args) {
        MyClass m = new MyClass("abc", 123);
        String s = (String) m.getA();
        System.out.println(s);
        Integer i = (Integer) m.getB();
        System.out.println(i);
      }
    }
    
    展开全文
  • 纯虚函数 、抽象类 、多重继承 、二义性问题 、菱形继承 、虚基类 、从内存布局看虚继承的底层实现原理


    纯虚函数

    纯虚函数是一种特殊的虚函数,在许多情况下,在基类中不能对虚函数给出有意义的实现,而把它声明为纯虚函数,它的实现留给该基类的派生类去做。这就是纯虚函数的作用。

    一般格式如下:

    class <类名>
    {
    	virtual <类型><函数名>(<参数表>)=0;};
    

    例如:

    class A
    {
    	virtual int funcation(int val) = 0; // 定义纯虚函数
    }
    

    纯虚函数可以让类先具有一个操作名称,而没有操作内容,让派生类在继承时再去具体地给出定义

    引入原因:

    • 为了方便使用多态特性,我们常常需要在基类中定义虚函数。
    • 在很多情况下,基类本身生成对象是不合情理的。例如,动物作为一个基类可以派生出老虎、孔雀等子类,但动物本身生成对象明显不合常理。

    为了解决上述问题,引入了纯虚函数的概念,即 将函数定义为纯虚函数

    若要使派生类为非抽象类,则编译器要求在派生类中,必须对纯虚函数予以重写以实现多态性。同时含有纯虚函数的类称为抽象类,它不能生成对象。这样就很好地解决了上述两个问题。


    抽象类

    凡是含有纯虚函数的类叫做抽象类。这种类不能定义对象,只是作为基类为派生类服务。但可以定义指针或引用

    除非在派生类中完全实现基类中所有的的纯虚函数,否则,派生类也变成了抽象类,不能实例化对象。在派生类实现该纯虚函数后,定义抽象类对象的指针,并指向或引用子类对象。

    一般而言纯虚函数的函数体是缺省的,但是也可以给出纯虚函数的函数体(此时纯虚函数变为虚函数),这一点经常被人们忽视。

    • 在定义纯虚函数时,不能定义虚函数的实现部分
    • 在没有重新定义这种纯虚函数之前,是不能调用这种函数的

    抽象类的唯一用途是为派生类提供基类,纯虚函数的作用是作为派生类中的成员函数的基础,并实现动态多态性

    继承于抽象类的派生类如果不能实现基类中所有的纯虚函数,那么这个派生类也就成了抽象类。因为它继承了基类的抽象函数,只要含有纯虚函数的类就是抽象类。

    纯虚函数已经在抽象类中定义了这个方法的声明,其它类中只能按照这个接口去实现。

    示例程序如下:

    #include <iostream>
    using namespace std;
     
    /*
    ** 抽象基类:不能被实例化的基类。 它仅仅只有一个用途,用来派生出其他类。
    ** 1. 要定义抽象基类,可使用纯虚函数,纯虚函数可当做接口使用
    ** 2. 基类的纯虚函数,在派生类中必须实现。 虚函数可以不用必须实现
    */
     
    /*定义抽象基类*/
    class Base 
    {
    public:
    
    	/*
    	** 虚函数=0,这个形式为纯虚函数,告诉编译器,必须在派生类中进行实现
    	** 可看成派生类的接口,调用此接口时,调用相应派生类的方法
    	*/
    	virtual void Fun() = 0;  
    };
     
    /*
    ** 实例化对象时,将创建两个对象,子对象和基类对象,
    ** 通过从调用的构造函数可以看出
    */
    class Derive: public Base
    {
    public:
    
    	/* 若不实现此函数,编译将会出错 */
    	void Fun() { cout << "Derive::Fun" << endl; } 
    	Derive() { cout << "Derive()" << endl; }
    	~Derive() { cout << "~Derive()" << endl; }
    };
     
    class Derive2: public Base
    {
    public:
    
    	/* 若不实现此函数,编译将会出错 */
    	void Fun() { cout << "Derive2::Fun" << endl; } 
    	Derive2() { cout << "Derive2()" << endl; }
    	~Derive2() { cout << "~Derive2()" << endl; }
    };
     
    void Show(Base& Base) {
    	Base.Fun();
    }
     
    int main()
    {
    	//Base base;  // error,抽象基类不可实例化对象
    	Derive derive; // 实例化对象
    	Derive2 derive2; // 实例化对象
    	
    	Base* base = &derive; 
    	Base* base2 = &derive2;
    	base->Fun();
    	base2->Fun();
    	
    	return 0;
    }
    

    我们可以看到,但我们给抽象基类实例化对象时,编译会报错如下:

    那么由下图我们可以看出,当我们使用基类指针指向不同的派生类对象时,调用Fun函数将调用基类指针所指对象的Fun函数:


    多重继承

    之前所介绍的单一继承是指:一个派生类只继承一个基类。

    多重继承指的是一个类可以同时继承多个不同基类的行为和特征功能

    语法格式如下:

    Class <类名><继承方式> <基类1><继承方式> <基类2>···
    {···}
    

    示例程序如下:

    class Base1
    {
    public:
    	Base1() { cout << "Base1()" << endl; }
    	~Base1() { cout << "~Base1()" << endl; }
    };
    class Base2
    {
    public:
    	Base2() { cout << "Base2()" << endl; }
    	~Base2() { cout << "~Base2()" << endl; }
    };
    
    /*
    **  : 之后称为类派生表,表的顺序决定基类构造函数
    ** 调用的顺序,析构函数的调用顺序正好相反
    */
    class Derive : public Base2, public Base1
    {};
    int main()
    {
    	Derive derive;
    	return 0;
    }
    

    上述程序算是一段简单的多重继承了,编译运行是没有错误的。平时绝大部分时候,我们都只使用单继承,所为单继承是针对多重继承而言的,即一个类只有一个基类

    我们看到运行结果是先是Base2构造,然后Base1构造:

    那么多重继承会带来各种各样的问题:

    • 二义性问题
    • 菱形继承导致派生类持有间接基类的多份拷贝

    二义性问题

    使用多重继承, 一个不小心就可能因为二义性问题而导致编译错误。

    最简单的例子,在上面的基类Base1和Base2中若存在相同的方法或成员变量,那么在派生类Derive中或使用Derive的对象时,若使用这个方法或成员变量时,那么编译器不知道需要调用Base1中的方法还是Base2中的方法或成员变量。

    当然我们可以给方法添加作用域来解决这个问题,我们也可以通过在派生类Derive中重新定义这个方法来覆盖基类中的同名方法,从而使编译器能够正常工作。

    示例如下:

    编译后,我们发现错误,即show函数的调用存在二义性问题:

    修改如下,我们为show函数加上作用域,即可正常运行:(另外一种解决方法是我们在Derive派生类中重写Show方法,将隐藏基类方法,程序也可正常运行)


    菱形继承

    我们来看一个示例图:

    • Derive1继承了Base类,它的成员有ma、mb、mc
    • Derive2继承了Base类,它的成员有ma、mb、md
    • Derive3继承了Derive1类和Derive2类,它的成员有ma、mb、mc、ma、mb、md

    我们发现了问题:Derive3由于多重继承,拿到了它的间接基类Base的两份数据拷贝,这并不是我们所期望的。

    这将会引起问题,例如,通常可以将派生类对象的地址赋给基类指针,但现在将出现二义性:

    Derive3 derive3;
    Base *base = &derive3; // error
    

    如下图所示:

    通常,这种赋值将把基类指针设置为派生类对象中的基类指针的地址。但是现在Derive3中包含两个地址可选择,所以应该使用类型转换来指定对象

    这将使得使用基类指针来引用不同的对象(多态性)复杂化。

    为了解决上述问题,C++引入了一种新技术——虚基类(virtual base class)。


    虚基类

    虚继承和虚函数是完全无相关的两个概念。

    虚继承是解决C++多重继承问题的一种手段,从不同途径继承来的同一基类,会在派生类中存在多份拷贝。这将存在两个问题:

    • 浪费存储空间
    • 存在二义性问题。

    通常可以将派生类对象的地址赋值给基类对象,实现的具体方式是,将基类指针指向继承类(继承类有基类的拷贝)中的基类对象的地址,但是多重继承可能存在一个基类的多份拷贝,这就出现了二义性

    虚基类使得从多个类(它们的基类相同)派生出的对象只继承一个基类对象。例如,通过在类声明中使用关键字 virtual ,可以使这些派生类只保留虚基类的一个副本。

    例如上例,如下声明后,Derive1 和 Derive2 虚继承了 Base后, Base 成为了Derive1 和 Derive2 的虚基类,那 Derive3 就可以安全的多继承 Derive1 和 Derive2了。如下图:

    从内存布局看虚继承的底层实现原理

    了解了虚基类的用法和作用后,我们来看一下虚基类的底层到底是怎样实现的
    之前我们介绍虚函数时,介绍了其实现原理即虚函数指针 vfptr 和虚函数表vftable。

    那么虚基类的实现是产生虚基类表指针 vbptr 与虚基类表 vbtable。

    虚继承底层实现原理与编译器相关,一般通过虚基类指针和虚基类表实现,每个虚继承的子类都有一个虚基类指针(占用一个指针的存储空间,4字节)和虚基类表(不占用类对象的存储空间)。

    需要强调的是,虚基类依旧会在派生类里面存在拷贝,只是仅仅只存在一份而已,并不是不在派生类里面了;当虚继承的派生类被当做基类继承时,虚基类指针也会被继承。

    实际上,vbptr指的是虚基类表指针(virtual base table pointer),该指针指向了一个虚基类表(virtual table),虚基类表中记录了虚基类与本类的偏移地址;

    通过偏移地址,这样就找到了虚基类成员,而虚继承也不用像普通多继承那样维持着公共基类(虚基类)的两份同样的拷贝,节省了存储空间。

    在这里我们可以对比虚函数的实现原理:他们有相似之处,都利用了虚指针(均占用对象的存储空间)和虚表(均不占用对象的存储空间)。

    • 虚基类依旧存在继承类中,只占用存储空间;虚函数不占用存储空间。
    • 虚基类表存储的是虚基类相对直接继承类的偏移;而虚函数表存储的是虚函数地址。

    接下来我们从内存布局看一下具体过程:
    首先看普通继承的内存布局:

    /* 普通继承(没有使用虚基类)*/
     
    // 基类A
    class Base
    {
    public:
    	int ma;
    };
     
    class Derive1 : public Base
    {
    public:
    	int mb;
    };
     
    class Derive2 : public Base
    {
    public:
    	int mc;
    };
     
    class Derive3 : public Derive1, public Derive2
    {
    public:
    	int md;
    };
    

    打开VS开发者命令行工具

    进入工程目录下,输入下述命令,注意/EHsc不一定要写,根据项目是否开启C++异常检查而定,最后加上类名即可

    我们得到Derive3的内存布局如下,我们发现 Derive3 拿到了其间接基类的两份拷贝:

    其基类Derive1和Derive2的内存布局如下:

    那么接下来我们定义Derive1和Derive2为虚继承,使得Base成为它们的虚基类。

    查看Derive1内存布局如下:

    我们看到了在Derive1内存的前4个字节中存储了vbptr虚基类指针,而虚基类的数据由之前的首部移至了尾部。

    并且我们看到在vbtable虚基类表中,offset偏移量字段显示为8,表示虚基类数据相对Derive1类首部的偏移量(向下偏移量)

    同样的,我们查看Derive2内存布局如下:

    其发生的变化和Derive1的是相同的。

    最后,我们查看一下 Derive3 的内存布局:

    同样的,我们发现,虚基类Base的数据移至了Derive3内存布局的末尾,并且只存在一份数据,并不是之前的两份,因此,我们验证了虚基类解决了多重继承中的菱形继承问题。

    实际上,vbptr指的是虚基类表指针(virtual base table pointer),该指针指向了一个虚表(virtual table),虚表中记录了vbptr与本类的偏移地址;第二项是vbptr到共有基类元素之间的偏移量。

    在这个例子中,虚表表明Derive3的间接基类Base的成员变量ma距离类Derive3开始处的位移为20,这样就找到了成员变量ma,而虚继承也不用像普通多继承那样维持着公共基类的两份同样的拷贝,节省了存储空间。


    查看内存布局:

    cl -d1reportSingleClassLayoutDerive 源.cpp
    Derive为类名 后边为源.cpp
    
    展开全文
  • 类的继承与多

    2012-03-01 12:29:02
    由圆和高多重派生掌握类的继承与派生类关系以及实现方法,理解类的层次结构; 掌握派生类构造函数初始化基类成员和对象成员的方法;理解赋值兼容规则,掌握派生类的复制构造函数和赋值运算符的定义
  • 当我们必须自己实现抽象方法时,我无法理解如何使用iterfaces实现多重继承?假设我有class A implements B,C{public void B(){//method of interface B implemented}public void C(){//method of interface C ...
  • 用户和内核 中断处理机制

    千次阅读 2021-01-15 22:57:54
    1.1.1 定义:什么是用户和内核? Kernel 运行在超级权限模式(Supervisor Mode)下,所以拥有很高的权限。按照权限管理的原则,多数应用程序应该运行在最小权限下。因此,很多操作系统,将内存分成了两个区域: ...
  • java 多态与多重继承

    2021-03-16 22:06:10
    package Learnbyoneself;import java.awt.CardLayout;public classPolymorphism {/*** java 中的每一中操作,操作的数据类型必须合法。...* 多性包括参数化多性和包含多性。多性语言具有...
  • 【C++】C++多性的一个典型例子

    千次阅读 2019-03-03 18:38:19
    Example:先建立一个Point...在本例中存在静态多性,这是运算符重载引起的(注意3个运算符函数是重载而不是同名覆盖,因为有一个形参类型不同)。可以看到,在编译时编译系统即可以判定应调用哪个重载运算符函数。
  • Java基础语法 接口(interface)的定义和实现 在学习接口之前,建议大家先熟悉一下前一篇文章对抽象的解释:Java基础语法 到底什么是抽象?,因为接口通俗的讲就是比抽象类更抽象的类,深入理解了抽象的概念之后,对...
  • static和多性sctatic定义常量静态方法静态块非静态块方法中的可变长个数的参数静态导入基本数据类型的对象缓存字符串缓存池面向对象设计思想的要点依赖关系关联关系继承关系多性三个定义和两个方法。多态分为两...
  • 性-运算符重载

    千次阅读 2016-07-21 22:56:50
    运算符重载是指对已有的运算符赋予多重含义。 必要性: C++中预定义的运算符其运算对象只能是基本数据类型,而不适合用户自定义的类型(如类类型)。 实现机制: 将指定的运算表达式转化为对运算符函数的调用,...
  • 科技信息 1.引言 多性(polymorphism)一词来源于拉丁语 ...Java 语言实现了两种多性:静态多性和动态多性。本文重点论述其采用重写机制实现动态多性的原理,并结合实例讲解动态多性的应用。 2.关于多态的...
  • 2021-01-15 22:11:42
    性 多性是发送消息给某个对象,让该对象自行决定响应何种行为。通过将子类对象引用赋值给超类对象引用变量来实现动态方法调用 public class Test1 { public static void main(String[] args) { Fa cc=new ...
  • 驯顺多重驱动

    2021-07-17 15:38:08
    多重驱动定义: 具有两个或更多个源的信号线 (net) 或信号 (signal) 称为多重驱动场景。 为何需要解决多重驱动场景? 多重驱动的存在属于设计错误,可能导致最终值难以确定。 因此针对具有多重驱动的信号线或...
  • 抽象类在面向对象的概念中,所有的对象都是通过类来表述的,但并不是所有的类都能够完整的描绘对象,...例如:定义一个平面图形Shape . 任何平面图形都有周长和面积,在Shape类中定义两个方法用于计算图形的面积和周长...
  • 头文件是拓展名为.h的文件,其包含了函数的声明和宏定义,它可以被多个源文件引用共享。头文件分为两种类型:编译器自带的系统头文件和程序员即用户编写的头文件。 引用头文件 1、引用系统头文件 编译器自带的系统...
  • 首先,Objective-C中不完全支持重载,网上很多人要么将重载和重写搞混,要么说OC不支持重载(当然按照重载严格定义说OC不支持重载也没错),事实上OC支持参数个数不同的函数重载。面试官:Objective-C和Swift中有...
  • 基于SPI FLASH的FPGA多重配置

    千次阅读 2018-10-12 15:05:06
     通过FPGA的多重配置可以有效...以Virtex5系列开发板和配置存储器SPI FLASH为基础,从硬件电路和软件设计两个方面对多重配置进行分析,给出了多重配置实现的具体步骤,对实现复杂硬件设计工程有一定的参考价值。 ...
  • 一方面它是有关继承和运算符重载内容的综合应用的例子,通过这个例子可以进一步融会贯通前面所学的内容,另一方面又是作为讨论多性的一个基础用例。希望大家耐心、深入地阅读和消化这个程序,弄清其中的每一个细节...
  • 多重继承(MI)

    2021-12-06 19:12:22
    这将使得使用基类指针来引用不同的对象(多性)复杂化。 包含两个Worker对象拷贝还会导致其他的问题。不过,真正的问题是:为什么需要Worker对象的两个拷贝?唱歌的侍者和其他Worker对象一样,也应只包含一个姓名和...
  • 面向对象基本定义及概念

    千次阅读 2015-08-15 14:30:57
    接口是可以多重继承的,一个接口可以继承多个接口使用 exetends 关键字表示继承,多个接口之间使用逗号“,”隔开。 接口和抽象类的区别 从编程的角度来看 , 两者相同的地方是都不能被实例化,都包含抽象方法...
  • 类的多

    千次阅读 2018-06-18 22:20:37
    在一个类中,可以定义多个同名的方法,只要确定它们的参数个数和类型不同。这种现象称为类的多态。多态使程序简洁,为程序员带来很大便利。在OOP 中,当程序要实现多个相近的功能时,就给相应的方法起一个共同的名字...
  • C#的多

    2021-09-29 21:31:31
    前言:各位csdn的源员们,大家好。我是小刘,初来乍到请大家多多指教,这是第n次发表博客,如有错误请大家观看后谅解,并在评论区留下您宝贵的意见,小刘将会用最大的努力去改正以及...多性意味着有多重形式。在..
  • 我们在这里考虑标准模型(SM),该模型扩展了具有多重N的单重标量,并与SM希格斯二重耦合。 在施加所有理论和实验约束并定义了EWPT强烈为一阶的区域后,我们获得了可以通过不同的未来指数达到GWs谱的区域
  • 随机推荐 Pythonn new-style class and old-style class In [1]: class old(): ...: a = 1 ...: In [2]: o = old() In [3]: o.__class__ Out[3]: 3.C#中泛型类的进一步探讨 阅读目录 一:多重泛型 class不仅可以有T,...
  • 面向对象基本特征类的...类的多性多性是指相同方法名的若干方法,具有不同的实现方式(即方法体不同)。多性有两种表现形式(1)方法重载(overloading):又称为静态多性,即同一类中可以有多个同名方法,但是...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 22,593
精华内容 9,037
关键字:

多重态定义