精华内容
下载资源
问答
  • 对象类模板

    2015-01-25 19:27:19
    模板的指导思想跟函数模板类似。  代码复用是面向对象设计中重要软件开发思想,对于软件开发效率很是关键。... 什么是类模板呢?类模板就是为类声明一种模板,使得类中某些数据成员,或某些

    类模板的指导思想跟函数模板类似。

           代码复用是面向对象设计中的重要的软件开发思想,对于软件开发效率很是关键。怎样做好代码复用呢?越是通用的代码越好复用,将类型作为参数,这种程序设计类型就是参数化程序设计。模板就是C++进行参数化设计的工具。利用模板可以使用同一段程序处理不同类型的对象。

           什么是类模板呢?类模板就是为类声明一种模板,使得类中的某些数据成员,或某些成员函数的参数,又或者是某些成员函数的返回值可以取任意的数据类型,包括基本数据类型和自定义数据类型。

           类模板的声明形式如下:

           template  <模板参数表>
           类声明

     template <class T>
            class Store
            {
            public:
                   ......
           private:
        ......
           };

           可以看到,在类的声明之前要加上一个模板参数表,模板参数表里的类型名用来说明成员数据和成员函数的类型。

           模板参数表中可以有以下两种模板参数:

           1.class  标识符(指明可以接受一个类型参数,就是说这是个不固定的类型,用它生成类时才会产生真正的类型)

           2.类型说明符  标识符(指明可以接受一个由“类型说明符”所指定类型的常量作为参数)

           模板参数表可以包含一个或多个以上两种参数,多于一个时各个参数之间用逗号分隔。有一点需要注意,类模板的成员函数必须是函数模板。实际上,类模板并不是有实际意义的代码,它只是一些具有相似功能的类的抽象,就是把这些类的共有部分写成模板,类型作为参数,只有用类模板生成类时才会根据需要生成实际的类的代码。

           用类模板建立对象时的声明形式为:

           模板<模板参数表>  对象名1,...,对象名n;

     Store<int> S1, S2;

           此处的模板参数表是用逗号分隔开的若干类型标识符或常量表达式构成。它与上面类模板声明时“模板参数表”中的参数是一一对应的。类型标识符与类模板中的“class  标识符”对应,常量表达式与“类型说明符  标识符”对应。这样声明对象之后系统会根据指定的参数类型和常量值生成一个类,然后建立该类的对象。

          下面是一个简单的例子:

            #include <iostream>
            using namespace std;

            // 定义结构体Student
            struct Student
            {
                      int   id;                 // 学号
                      float average;    // 平均分
            };

            // 类模板,实现对任意类型的数据进行存取
            template <class T>
            class Store
            {
            public:
                     Store(void);              // 默认形式(无形参)的构造函数
                     T GetElem(void);    // 获取数据
                     void PutElem(T x);  // 存入数据
           private:
                     T item;                   // item用来存放任意类型的数据
                     int haveValue;      // 标识item是否被存入数据
           };
           // 以下是成员函数的实现,注意,类模板的成员函数都是函数模板
           // 构造函数的实现
           template <class T>
           Store<T>::Store(void):haveValue(0)
           {
           }
           // 获取数据的函数的实现
           template <class T>
           T Store<T>::GetElem(void)
           {
                     // 若item没有存入数据,则终止程序
                    if (haveValue == 0)
                   {
                              cout << "item没有存入数据!" << endl;
                              exit(1);
                   }
                   return item;
           }
           // 存入数据的函数的实现
           template <class T>
           void Store<T>::PutElem(T x)
           {
                   haveValue = 1;     // 将其置为1,表示item已经存入数据
                   item = x;                // 将x的值存入item
           }

           int main()
           {
                    // 声明Student结构体类型变量,并赋初值
                   Student g = { 103, 93 };
                   // 声明两个Store类的对象,数据成员item为int类型
                   Store<int> S1, S2;
                   // 声明Store类对象S3,数据成员item为Student结构体类型
                   Store<Student> S3;


                   S1.PutElem(7);    // 向对象S1中存入数值7
                   S2.PutElem(-1);   // 向对象S2中存入数值-1
                   // 输出S1和S2的数据成员的值
                   cout << S1.GetElem() << "  " << S2.GetElem() << endl;

                   S3.PutElem(g);    // 向对象S3中存入Student结构体类型变量g
                    // 输出对象S3的数据成员
                   cout << "The student id is " << S3.GetElem().id << endl;

                   return 0;
            }

           上面这个程序的运行结果是:

           7  -1
           The student id is 103

           类是对对象的抽象,类模板是对类的抽象。



    展开全文
  • 和函数模板类似,都为了提高代码复用性,这面向对象设计中软件开发重要思想之一。 定义如下: template 声明建立对象声明:模板对象名1,….对象名n;下面直接上代码: #include #include using ...
    和函数模板类似,都是为了提高代码的复用性,这是面向对象设计中软件开发重要的思想之一。
    定义如下:
    
    template<模板参数表>
    类声明
    建立对象时的声明:
    模板<模板参数表>对象名1,….对象名n;
    下面直接上代码:
    #include <iostream>
    #include <string>
    using namespace std;
    struct Person   //定义一结构体类型
    {
    	int id;
    	string name;
    };
    
    template<typename T> //该类用于存储数据类型
    class Store
    {
    public:
    	Store(void);  //无参构造函数
    	T GetItem();  //取得存储值
    	void putItem(T t);  //存储数据
    private:
    	T item;  //存储项目
    	int isStore;  //是否存储标志
    };
    
    template<typename T>
    Store<T>::Store(void):isStore(0)  //默认未存储
    {
    }
    
    template<typename T>
    T Store<T>::GetItem() 
    {
    	if(isStore==0)
    	{
    		cout<<"no data"<<endl;
    		exit(1);
    	}
    	else
    		return item;
    }
    
    template<typename T>
    void Store<T>::putItem(T t)
    {
    	item=t;
    	isStore=1;
    }
    int main()
    {
    //	Person p={1,"tqtiimy")};  //vc6报错,string不能用初始值列表初始化
    //一开始也觉得奇怪,后面查后才知道是前期编译器不支持,升级之后是没有问题的
    	Person p;  //创建一结构体对象
    	p.id=1;
    	p.name="tqtiimy";
    	Store<int> s1;        //以int类型创建Store对象
    	Store<Person> s2;    //以Person结构体类型
    	s1.putItem(22);
    	s2.putItem(p);        
    	cout<<s1.GetItem()<<endl;   //这里Store类的复用性明显提高了,根据实际需要生成不同模板
    	cout<<s2.GetItem().name<<endl;
    	return 0;
    }


    展开全文
  • 1.首先区别模板类是在建立对象还是在调用经重载()函数: 也许这个标题很迷,但是我这个小白在做题时确实被搞糊涂了。。。不过()重载确实经常用到,在这里总结一下。 首先说个大致形式: 如果在类模板中有...

    类模板中重载的():

    ()的重载很特殊,因为如果一个类重载了()那么该类的对象就称为函数对象。也就是这个类的对象可以作为函数被调用或者作为函数指针传入其他函数。我们在重载()时一定要根据他所在位置的作用来判断他的返回类型以及函数体、参数!!!

    1.首先是区别模板类是在建立对象还是在调用经重载的()函数:

    也许这个标题很迷,但是我这个小白在做题时确实被搞糊涂了。。。不过()的重载确实经常用到,在这里总结一下。
    首先说个大致形式:
    如果在类模板中有()的重载函数:函数返回值类型 operator ()(形参){ }。在main中如果是:类名<数据类型> ( ) (传入的实参);那么就是在调用重载的()函数,如果是类名<数据类型> (传入的实参);那么就是在定义对象并调用构造函数。因为会有好多括号容易有些懵逼,看两道最近做的程序填空题:
    第一题是调用重载的()函数:

    /*
    编写GoodCopy类模板,使得程序按指定方式输出
    输入:
    第一行是整数 t,表示数据组数
    每组数据:
    第一行是整数 n , n < 50
    第二行是 n 个整数 
    第三行是 n 个字符串
    
    输出;
    将输入的整数原序输出两次,用","分隔
    然后将输入的字符串原序输出两次,也用 ","分隔
    
    样例输入
    2
    4
    1 2 3 4
    Tom Jack Marry Peking
    
    样例输出
    1,2,3,4,
    1,2,3,4,
    Tom,Jack,Marry,Peking,
    Tom,Jack,Marry,Peking,
    */
    #include <iostream>
    using namespace std;
    
    
    template <class T>
    struct GoodCopy {
    //补充你的代码
    };
    int a[200];
    int b[200];
    string c[200];
    string d[200];
    
    template <class T>
    void Print(T s,T e) {
    	for(; s != e; ++s)
    		cout << * s << ",";
    	cout << endl;
    }
    
    int main()
    {
    	int t;
    	cin >> t;
    	while( t -- ) {
    		int m ;
    		cin >> m;
    		for(int i = 0;i < m; ++i)	cin >> a[i];
    		GoodCopy<int>()(a,a+m,b);
    		Print(b,b+m);
    		GoodCopy<int>()(a,a+m,a+m/2);
    		Print(a+m/2,a+m/2 + m);
    
    		for(int i = 0;i < m; ++i)	cin >> c[i];
    		GoodCopy<string>()(c,c+m,d);
    		Print(c,c+m);
    		GoodCopy<string>()(c,c+m,c+m/2);
    		Print(c+m/2,c+m/2 + m);
    	}
    	return 0;
    }
    

    我们可以看出这就是再让我们实现 GoodCopy类模板,而 GoodCopy在main中的作用就是把一个区间内的数据传给另一个容器,另外的a,a+m,a+m/2和c,c+m,c+m/2就是关于指针的移动了在这里不是重点。
    补充的代码是:

    	//your code starts here
    	void operator()(T* s,T* e,T* x) 
    	{ 
    		bool backward = false;
    		T * tmp;
    		for(tmp = s;tmp!= e; ++tmp) {
    			if( tmp == x ) {
    				backward = true;
    				break;
    			}
    		}
    		if( !backward) {
    			for(; s != e; ++s,++x)
    				* x = * s;
    		}
    		else {
    			T * p = x;
    			for(tmp = s; tmp != e; ++tmp,++p);//在main中p就指向了a+m/2+m
    			--p;//因为e(也就是a+m/2+m)只是临界值不会输出故--得到a+m/2+m-1
    			T * q = e;
    			-- q;
    			for(; q != s; --q, --p)//开始让p从m+m/2~m/2+1获得 q从m~1的值 
    				* p = * q;
    			*p = * q;//最开始s(a[0])在这传进
    		}
    	}
    //your code ends here	
    

    因为这是程序填空题,不能按自己写的方式去想,而是应该看题目中的GoodCopy<int>()(a,a+m,b);显然是在调用函数而不是定义对象,所以在类中的()重载的函数的形参一定要是三个,分别对应a,a+m,b

    第二题是先定义对象调用构造函数再调用重载的()函数

    /*程序填空输出指定结果
    
    输入
    多组数据每组数据两行 
    第一行是两个整数 m 和 n
    第二行先是一个整数k ,然后后面跟着k个整数
    
    输出
    对每组数据,按原顺序输出第二行的后k个整数中,大于m且小于n的数输出两遍,数据保证一定能找到符合要求的整数 
    
    输入样例
    2 8
    5 1 2 3 4 9
    
    输出样例
    3,4,
    3,4,
    */ 
    
    #include <iostream>
    #include <vector>
    using namespace std;
    
    struct A {
    	int v;
    	A() { }
    	A(int n):v(n) { };
    	bool operator<(const A & a) const 
    		return v < a.v;
    };
    //你的代码
    
    template <class T>
    void Print(T s,T e)
    {
    	for(;s!=e; ++s)
    		cout << *s << ",";
    	cout << endl;
    }
    template <class T1, class T2,class T3>
    T2 Filter( T1 s,T1 e, T2 s2, T3 op) 
    {
    	for(;s != e; ++s) {
    		if( op(*s)) {
    			* s2 = * s;
    			++s2;
    		}
    	}
    	return s2;
    }
    
    ostream & operator <<(ostream & o,A & a)
    {
    	o << a.v;
    	return o;
    }
    vector<int> ia;
    vector<A> aa; 
    int main()
    {
    	int m,n;
    	while(cin >> m >> n) {
    		ia.clear();
    		aa.clear(); 
    		int k,tmp;
    		cin >> k;
    		for(int i = 0;i < k; ++i) {
    			cin >> tmp; 
    			ia.push_back(tmp);
    			aa.push_back(tmp); 
    		}
    		vector<int> ib(k);
    		vector<A> ab(k);
    		vector<int>::iterator p = Filter(ia.begin(),ia.end(),ib.begin(),FilterClass<int>(m,n));
    		Print(ib.begin(),p);
    		vector<A>::iterator pp=Filter(aa.begin(),aa.end(),ab.begin(),FilterClass<A>(m,n));
    		Print(ab.begin(),pp);
    		
    	}
    	return 0;
    }
    

    看main中Filter模板函数的参数要调用的FilterClass是一个类模板形式的,这里就是在定义对象了,所以我们要写构造函数,并且进入Filter模板函数的定义中看看FilterClass类模板的对象如何作用,是 op(*s),也就是作为一个函数被调用,那么这个函数就是()的重载函数。
    插入的代码:

    //your code starts here
    
    template <class T>
    class FilterClass
    {
    	private:
    		T minV,maxV;
    	public:
    		FilterClass(T mi,T ma):minV(mi),maxV(ma) { };
    		bool operator()(const T & v) const {//就是op()
    			return minV < v && v < maxV;
    		}
    };
    //your code ends here
    

    2.函数对象作为函数指针传入其他函数

    先看一个例子(对比第一点中的两个例子,会有更多心得):

    /*程序填空,输出指定结果 
    输入
    多组数据,每组一行,是一个整数n和一个字符串s
    
    输出
    定义两个整数的距离为两个整数差的绝对值
    定义两个字符串的距离为两个字符串长度差的绝对值  
    对每组数据:
    对数组a按和n的距离从小到大排序后输出。距离相同的,值小的排在前面。
    然后对数组b,按照和s的距离从小到大输出。距离相同的,字典序小的排在前面
    
    样例输入:
    2 a123456
    
    样例输出:
    1,3,0,4,7,8,9,10,15,20,
    American,Peking,123456789,Jack,To,abcdefghijklmnop,
    */
    
    #include <iostream>
    #include <cmath>
    #include <algorithm>
    #include <string>
    using namespace std;
    template <class T1,class T2>
    struct Closer {
    //填入你的代码
    };
    
    int Distance1(int n1,int n2) {return abs(n1-n2);}
    int Distance2(const string & s1, const string & s2){return abs((int)s1.length()- (int) s2.length());}
    int a[10] = { 0,3,1,4,7,9,20,8,10,15};
    string b[6] = {"American","Jack","To","Peking","abcdefghijklmnop","123456789"};
    int main()
    {
    	int n;string s;
    	while( cin >> n >> s ) {
    		sort(a,a+10,Closer<int ,int (*)(int ,int)> (n,Distance1));
    		for(int i = 0;i < 10; ++i) cout << a[i] << "," ;
    		cout << endl;
    		sort(b,b+6,Closer<string,int (*)(const string &,const string &  )> (s,Distance2)); 
    		for(int i = 0;i < 6; ++i) cout << b[i] << "," ;
    		cout << endl;
    	}
    	return 0;
    }
    

    可以看出Closer类作为sort函数的第三个参数,也就是排序的规则函数,而被调用的显然是Closer这个类的对象,而不是直接调用()的重载函数,所以我们在构造Closer类时一定要让n和distance为数据成员,重载()的参数是比较的内容而不是用于比较的函数(distance),这样才符合。
    填入的代码:

    struct Closer {
    // 在此处补充你的代码
    	T1 n;
    	T2 op;
    	Closer(T1 m,T2 dis):n(m),op(dis) {}
    	bool operator () (const T1 & v1,const T1 & v2){
    		if(op(v1,n)!=op(v2,n)){
    			return op(v1,n)<op(v2,n);
    		}else{
    			return v1<v2;
    		}
    	} 
    };
    
    展开全文
  • 既然对象是以类为模板生成的,那么类又是以什么为模板生成的? 元类具有动态改变类的能力,给编程带来了更方便的动态性和能力。 新型类相比于传统类,支持更多特性和机制,有更多的弹性。 文章目录 元类 类工厂 初始...

    在这里插入图片描述

    元类


    既然对象是以类为模板生成的,那么类又是以什么为模板生成的?

    事实上绝大部分情况下都都不是必须使用元类才能完成开发,但是元类动态地生成类的能力能更方便地解决下面情景的难题:

    • 类在设计时不是所有细节都能确定,有些细节需要程序运行时得到的信息才能决定。
    • 类比实例更重要的情况,如用声明性语言在类声明中直接表示了它的程序逻辑,使用元类来影响类的创建过程就相当有用。

    类工厂


    在Python老版本中,可以使用类工厂函数来创建类,返回在函数体内动态创建的类。
    类工厂的方法是通过一个函数来生产不同的类。类工厂可以是类,就像它们可以是函数一样容易。
    例如:

    def class_with_method(func):
        class klass: pass
        setattr(klass, func.__name__, func)
        return klass
    def say_tip(self):
        print('记得一键三连~')
    Tip = class_with_method(say_tip)
    tip = Tip()
    tip.say_tip()
    

    函数class_with_method是一个类工厂函数,通过setattr()方法来设置类的成员函数,并且返回该类,这个类的成员方法可以通过class_with_methodfunc参数来指定。
    在这里插入图片描述

    初始元类


    在Python2.2之后,type特殊类就是这样的类工厂,即所谓的元类,元类是类的类,类是元类的实例,对象是类的实例。
    元类type使用方法:

    def say_tip(self):
        print('记得一键三连~')
    Tip = type('Tip',(),{'say_tip':say_tip})
    tip = Tip()
    tip.say_tip()
    

    在这里插入图片描述
    元类type首先是一个类,所以比类工厂的方法梗灵活多变,可以自由的创建子类来继承扩展元类的能力。例如:

    class ChattyTypr(type):
        def __new__(cls, name, bases, dct):
            print("分配内存空间给类",name)
            return type.__new__(cls, name, bases, dct)
        def __init__(cls, name, bases, dct):
            print("初始化类", name)
            super(ChattyTypr, cls).__init__(name, bases, dct)
    a = ChattyTypr('Test',(),{})
    

    在这里插入图片描述

    其中,__new__分配创建类和__init__方法配置类是类type内置的基本方法,需要注意的是,第一个蚕食是cls(特指类本身)而非self(类的实例)。

    元类实例化一个类时,类将会获得元类所拥有方法,就像类实例化对象时对象获得类所拥有方法一样,但是注意多次实例化和多次继承的区别:
    在这里插入图片描述

    元类属性


    Python中每一个类都是经过元类实例化而来,只不过这个实例化过程在很多情况下都是由Python解释器自动完成的。那么怎么设置元类的属性?
    每个类都有一个属性__metaclass__用来说明该类的元类,该属性一般由解释器自动设置,不过用户也可以更改该属性来更改类的元类。可以在类的内部直接设置__metaclass__属性,也可以设置全局变量,那么该命名空间下定义所有类的元类都将是全局变量__metaclass__所指定的元类。

    class ChattyTypr(type):
        def __new__(cls, name, bases, dct):
            print("分配内存空间给类",name)
            return type.__new__(cls, name, bases, dct)
        def __init__(cls, name, bases, dct):
            print("初始化类", name)
            super(ChattyTypr, cls).__init__(name, bases, dct)
    class example(metaclass=ChattyTypr):
        def __init__(self):
            print('初始化')
    

    在这里插入图片描述
    在这里插入图片描述

    元类作用


    改变全局变量__metaclass就能改变类的元类,而类又是元类的实例化结果,所以元类可以改变类的定义过程。换句话说,只要改变全局变量__metaclass__就能改变类的定义,这就是元类的作用了。

    class example:
        def __init__(self):
            print('类example初始化')
        def say_tip(self):
            print('记得一键三连')
    a = example()
    a.say_tip()
    class change(type):
        def __new__(cls, name, bases, dict):
            def say_tip(self):
                print('记得点赞关注收藏~')
            dict['say_tip']=say_tip
            return type.__new__(cls, name ,bases, dict)
    class example(metaclass=change):
        def __init__(self):
            print('类example初始化')
        def say_tip(self):
            print('记得一键三连')
    a = example()
    a.say_tip()
    

    在这里插入图片描述

    面向方面和元类


    元类的作用能带来什么实用价值吗?
    实际用途确实有的,接近于面向方面编程(Aspect Oriented Programming,AOP)的核心内容,即所谓的“横切关注点”。

    使用面向对象方法构建软件系统,我们可以利用OO的特性很好地解决纵向问题,因为OO的核心概念(如继承等)都是纵向结构的。
    但是软件系统中往往很多模块/类共享某个行为,或者说某个行为存在于软件的各个部分中,看作是横向 存在于软件之中,它所关注的是软件个部分共有的一些行为,而且很多情况下这种行为不属于业务逻辑的一部分。

    一个软件系统的业务逻辑很大一部分代码都是AOP里所说的横切关注点。例如日志处理、安全检测、事务处理、权限检测等占比很大,几乎每个地方都要调用。AOP的思想就是把这些横切关注点代码都抽取出来,不再在各个软件模块中显示使用。

    以日志处理为例,一般习惯在做一些操作前写上开始模块处理的每个步骤都需要由正常日志和异常日志,那么这个软件光是写日志的代码就要成千上万行了,维护起来相当困难。

    如果部分代码不需要手工写到各个业务逻辑处理的地方,而是把这部分代码独立出来,那么在各个业务逻辑处理的地方,会在运行的时候自动调用这些横切关注点功能,这样代码量就少很多,这就是AOP的核心思想。

    要实现AOP所说的自动调用,有的语言使用AspectJ编译器,Python则使用元类。

    小结


    元类具有动态改变类的能力,给编程带来了更方便的动态性和能力。
    实际使用过程中,需要防止过度使用元类来改变类,过于复杂的元类通常会带来代码难以和可读性差的问题,所以一定要在确实需要使用是再使用元类。

    新型类


    Python在2.2版本后,新引入了两种不同的类:新型类和传统类/经典类。Python的对象世界相比也发生了重大变化。

    新型类VS传统类


    老版本的Python中不是所有的元素都是对象,内置的数值类型都不能被继承,而在版本2.2后,任何内建类型也都是继承自object类的类,凡是继承自类object或者object子类的类都是新型类,而不是继承自object或object子类的都成为传统类

    新的对象模型于传统模型相比有小但是很重要的优势,Python版本对传统类的支持主要是为了兼容性,所以使用类的时候推荐从现在开始直接使用新型类。在Python3版本将放弃兼容性,即Python3.X版本中只存在新型类。

    新型类继承自object或object子类,实际上所有的内建类型都是从object继承而来,可以用issubclass()函数验证,当存在子类和父类关系时返回True,否则返回False。
    在这里插入图片描述

    插播反爬信息 )博主CSDN地址:https://wzlodq.blog.csdn.net/

    静态方法和类方法


    新的对象模型提供了两种类的方法:静态方法和类方法。

    静态方法可以直接被类或类的实例调用,没有常规方法的那样限制(绑定、非绑定、默认第一个参数规则等),即静态函数的第一个参数不需要指定为self,也不需要只有对象(类的实例)才能调用。使用关键字@staticmethod定义。

    如下定义静态方法、常规方法(第一个参为self和不带self两种)

    class Test(object):
        @staticmethod
        def static_tip(str):
            print(str)
        def normal_tip(str):
            print(str)
        def normal_tip2(self,str):
            print(str)
    
    • 使用类调用
      直接使用类调用时,不需要传入self表示具体的类的实例,即报错只传了一个参数。
      在这里插入图片描述
    • 使用对象(类的实例)调用
      使用对象调用时,自动将类实例对象作为第一个参数传给该方法,即报错给了两个参数。
      在这里插入图片描述

    类方法不管是使用类来调用还是使用对象(类的实例)来调用,都是将类作为第一个参数传入。使用关键字@classmethod定义。
    在这里插入图片描述

    特定方法


    1. __new__方法
      当一个类C调用C(*args,**kwds)创建一个C类实例时,Python内部实际上调用的是C.__new__(C,*args,**kwds)。new方法的返回值x就是该类的实例对象,new即用来分配内存生成类的实例。
      注意第一个参数是cls(即这里写的类C),用来接受一个类参数,然后才能返回该类的实例。
      在这里插入图片描述
      使用new方法可以实现一些传统类无法做到的功能,例如让类只能实例化一次:
      在这里插入图片描述
    2. __init__方法
      当调用new方法分配内存创建一个类C对象后,Python判断该实例是该类的实例,然后会调用C.__init__(x,*args,**kwds)来初始化这个实例,x就是new方法的返回值,init即对类实例对象做初始化操作。
      注意第一个参数是self(即这里写的x)表示接受类的实例对象。
      在这里插入图片描述
      上述实例化对象代码c = C()就等价于:
      在这里插入图片描述
    3. __getattribute__方法
      __getattribute__负责实现对象属性引用的全部细节。新型类在调用它自身的类或方法是,实际上都是先通过该方法来调用。
      在这里插入图片描述
      因为新型类调用自身属性和方法时都会先调用__getattribute__方法,所以可以实现一些新功能,如隐藏父类的方法:
      在这里插入图片描述

    特定属性


    内建property类用来绑定类实例的方法,并将其返回值绑定为一个类属性,语法:
    attrib = property(fget=None, fset=None, fdel=None, doc=None)

    设类C通过property创建了属性attrib,x是类C的一个实例。

    • 当引用x.attrib时,会调用fget()方法取值;
    • 当为x.attrib赋值时,会调用fset()方法;
    • 当执行删除del x.attrib时,会调用fdel()方法;
    • doc参数为该属性的文档字符串。

    如果不定义fset()fdel()方法,那么该属性将是一个只读属性。

    property可以方便地将一个函数的返回值转换为属性,这下操作就很灵活方便了。
    比如定义一个长方形类,如果要将它的面积也作为一个属性,就可以用property将计算面积的方法绑定为一个属性:

    class Rectangle(object):
        def __init__(self,width,height):
            self.width=width
            self.height=height
        def getArea(self):
            return self.width*self.height
        area = property(getArea(),doc='长方形的面积')
    

    上述代码中,getArea()是计算面积的方法,使用property将该方法的返回值转换为属性area,这样引用Rectangle的area是,Python会自动使用getArea()计算出面积。同时由于该例中只定义了fget()方法,所以area是一个只读属性。

    super()方法


    新型类提供了一个特殊的方法super()super(aclass,obj)返回对象obj是一个特殊的超对象(superobject)。当我们调用该超对象的一个属性或方法时,就保证了每个父类的实现均被调用且仅仅调用了一次。

    以下时直接调用父类的同名方法,无法避免类A的方法被重复调用:

    class A(object):
        def test(self):
            print('A')
    class B(A):
        def test(self):
            print('B')
            A.test(self)
    class C(A):
        def test(self):
            print('C')
            A.test(self)
    class D(B,C):
        def test(self):
            print('D')
            B.test(self)
            C.test(self)
    d = D()
    d.test()
    

    在这里插入图片描述

    以下时使用super()方法,保证父类方法均调用一次:

    class A(object):
        def test(self):
            print('A')
    class B(A):
        def test(self):
            print('B')
            super(B, self).test()
    class C(A):
        def test(self):
            print('C')
            super(C, self).test()
    class D(B,C):
        def test(self):
            print('D')
            super(D, self).test()
    d = D()
    d.test()
    

    在这里插入图片描述

    小结


    新型类相比于传统类,支持更多特性和机制,有更多的弹性。例如可以定制实例化的过程,尤其时在多重继承的情况下能避免传统类存在的缺陷。而事实上Python3.X版本中已经不存在传统类了,目前传统类存在的意义主要是为了保持之前的兼容性。

    Python系列博客持续更新中

    原创不易,请勿转载本不富裕的访问量雪上加霜
    博主首页:https://wzlodq.blog.csdn.net/
    微信公众号:唔仄lo咚锵
    如果文章对你有帮助,记得一键三连❤

    展开全文
  • 模板的指导思想跟函数模板类似。  代码复用是面向对象设计中重要软件开发思想,对于软件开发效率很是关键。... 什么是类模板呢?类模板就是为类声明一种模板,使得类中某些数据成员,或
  • C++对象的模板

    2014-06-05 23:50:02
    在程序设计中往往尊在这样两种情况,一种两个或duo
  • java反射java反射常用方法获取类模板通过类模板对象创建实体对象类中未定义有参或无参构造器的情况下创建对象不调用方法尝试给一个类的私有属性赋值通过反射获取一个类的父类,并获取它实现的接口 java反射 ...
  • java的对象是放在栈内存; java实例是放在堆内存(new 出对象数据)。 比如: 注意:静态方法中没有对象,自然就没有this,super(内存角度考虑,是静态东西在类模板中生成,而对象时new出来...
  • 设想一个使用场景:有各种类型对象A,B,C...,这些对象在系统中创建和使用相分离,如何搬运这些不同类型数据对象?...考虑有一个包裹Wrapper,里面可以存放各种类型的对象,可能写如下 tem
  • 类模板模板类

    万次阅读 多人点赞 2019-07-04 21:10:42
    使用类模板定义对象时,系统会实参的类型来取代类模板中虚拟类型从而实现了不同类的功能。 定义一个类模板与定义函数模板的格式类似,必须以关键字template开始,后面尖括号括起来的模板参数,然后类名,其格式...
  • 类是在对象之上的抽象,对象是类的具体化,是类的实例。类与对象有什么关系?类和对象之间是抽象与具体的关系。类是一个模板,是对一类事物的抽象描述,而对象用于表示现实中该事物的个体。类是在对象之上的抽象,...
  • 面向对象最重要的概念就是(Class)和实例(Instance),必须牢记类是抽象的模板,比如Student,而实例根据创建出来的一个个具体的“对象”,每个对象都拥有相同的方法,但各自的数据可能不同。仍以Student为...
  • 模板是模板的一种, 可以在使用时确定类的类型。  类模板不是一个类,不能直接用于生成对象。 Foo f;错误的。 template< class T> class Foo { T tVar; //... };  模板类 就是 类模板...
  • 接着来学习类模板作为函数参数传入如何使用,如果需要把类模板作为参数一起传入到函数中,一般有三种情况,下面分别用代码来解释这三种情况。 1.指定传入类型 就是在参数中,就指定类型,而不是<class T1, ...
  • 声明为当前类的友元,那么主要被声明的(类/成员函数/全局函数(或他们的模板))获得了访问当前类的私有成员的特权; 要么通过传参(主动声明者的对象为参数)的形式访问,要么同过成员对象的方式来访问成员对象的私有成员.*...
  • 类模板可以实例化对象的,因此类模板也可以做函数参数。 1、作用 类模板实例化出的对象,向函数传参方式。 2、一共有三种传入方式: 指定传入类型:直接显示对象的数据类型 参数模板化:将对象参数变为...
  • 类:主管抽象,是对象的模板,可以实例化对象。习惯上类的定义格式:定义属性:实例变量。格式:[修饰符] 类型 变量名 [=?]实例变量定义在类中但在任何方法之外。实例变量有默认值:各种各样的0.(通数组)实例变量的...
  • 什么是类? 类:是一组相关属性和行为的集合。可以看成一类事物的模板,使用事物的属性和行为特征来描述该类事物。...类是对象的模板对象是类的实体。 类可以细分,但细分的不一定是对象。 类的定义 事物与类.
  • 2、使用类模版的文件组织:网上的说法类的定义以及类中函数的实现放到同一个文件中,然后在主文件中进行引用。还有一种方法参考gem5的组织方式,把类的定放到一个头文件中,把类中各函数的实现放到令一个...
  • 如果对一个定义了两个或多个对象,则这些同类的对象之间可以互相赋值,或者说,一个对象的值可以赋给另一个同类的对象。这里所指的对象的对象中所有数据成员值。 对象之间赋值也通过赋值运算符"=...
  • 二、类和对象1、类的概念面向对象编程的2个非常重要的概念:类和对象是面向对象编程的核心。在使用对象的过程中,为了将具有共同特征和行为的一组对象抽象定义,提出了另外一个新的概念——类。(1)类是对象的模板,...
  • 类模板

    2019-05-25 20:45:08
    1.对于类模板来说,其功能相同,但数据类型不同。 2.关于类模板的声明和类模板对象的声明方法。 类模板声明:template<class 类型参数名> 类模板对象的声明:类模板名<实际类型名> 对象名(参数...
  • C# 对象缓冲池模板类

    千次阅读 2008-06-15 16:57:00
    一个比较好的选择使用缓冲池,下面的代码我在编写股票程序时所写的一个缓冲池代码,因为考虑到会用的比较广泛,我花时间将它写成了通用的模板类。现在提供出来,如果有需要,你可以直接使用。 下面缓冲池的...
  • 模板类模板

    2013-08-14 14:17:35
    如果说类是对象的抽象,对象是类的实例,则类模板是类的抽象,类是类模板的实例。利用类模板可以建立含各种数据类型的类 eg:vector。 补充:类模板模板类的区别 类模板(class template)说明的是该类的一个模板...
  • 所谓函数模板,实际上建立一个通用函数,其函数类型和形参类型不具体指定,用一个虚拟类型来代表。这个通用函数就称为函数模板。凡是函数体相同函数都可以用这个模板来代替,不必定义多个函数,只需在模板中...
  • 对象类的关系

    2017-08-01 20:34:41
    对象 以类为模板是类的一个实例,是类的具体的表现形式 类: 是对对象的抽象,对具有特定功能的对象的抽象描述 从源码角度上看:先有类 再有对象 从分析层面上看:先有对象后有类 从现实世界上看:先有对象...
  • 一、什么是类1.类其实就是类型、是模板,是对象的一种抽象。...通俗来说:对象是类的一个个独立的个体,类是对象的类型、模板2.严格定义:类是对象的抽象、对象是类的实例3.是先有类还是先有对象?如果站在...
  • 二、类和对象1、类的概念面向对象编程的2个非常重要的概念:类和对象是面向对象编程的核心。在使用对象的过程中,为了将具有共同特征和行为的一组对象抽象定义,提出了另外一个新的概念——类。(1)类是对象的模板,...
  • 函数模板类模板的区别

    千次阅读 2017-07-18 23:16:42
    转自:函数模板与类模板有什么区别? 答:函数模板的实例化由编译程序在处理函数调用时自动完成的,而类模板的实例化必须由...这期间有涉及到函数模板模板函数,类模板模板类的概念 (类似于类与类对象的区别)

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 15,196
精华内容 6,078
关键字:

对象是类的模板