c++十四天(类的静态成员和模板函数)

22 篇文章 2 订阅
6 篇文章 0 订阅

目录

一、static关键字(C语言)

二、类中的静态成员特点

三、类中的静态成员函数特点

四、类中const成员

五、类中的const 成员函数特点

六、类中的const 对象特点

七、模板

八、模板函数与普通函数区别

九、模板函数的局限性

十、模板类

模板类作为参数

十一、模板类的成员函数类外编写

十二、模板类的继承

总结:


一、static关键字(C语言)

1、static 修饰的变量就是静态数据 。
2、静态数据只能被初始化一次 。
3、静态数据存储在数据段。  
4、静态全局变量,只能在当前文件中使用。

二、类中的静态成员特点

1、类的静态数据成员,不包含在类的空间中。  (静态数据:存储在数据段)。

2、类的静态数据成员,无法在类内初始化!    (只能在类外初始化)。

    int base::data = 100;   //类外初始化类中的静态成员 。

3、类的权限还是可以影响静态数据成员的(假设该数据成员是公有则可以不用定义对象访问)。  

     cout << base::data << endl;     //直接通过类名访问。

4、类中的静态数据成员是所有该类的对象共享的。

#include <iostream>
using namespace std;

class  base {
public: 
base(){}

void set_data(){
    data = 123456;
}

public:

static int data;  //静态数据成员 
};

int base::data = 100; //类外初始化类中的静态成员 

int main()
{
    
    base  a; 
    a.data = 10086; 

    base b; 
    cout << a.data << endl; 
    cout << b.data << endl; 

    b.data = 10010; 
    cout << a.data << endl; 
    cout << b.data << endl; 

    a.set_data(); 
    cout << a.data << endl; 
    cout << b.data << endl; 
}

三、类中的静态成员函数特点

1、类中的静态成员函数无法使用 this 指针 。

2、类中的静态成员函数无法使用 非静态数据。    (因为静态成员函数是先于类存在的)

3、类中的静态成员函数可以直接调用。          (不需要创建对象)

#include <iostream>
using namespace std;

int  value=10086;

class base {
public: 
//静态成员函数 
static void set_data(int d){
   // base::data = d;  无法访问非静态数据 
      value = d; //因为value 存储在数据段 ,是先于 main 函数存在的
      my_data = d;//类中的静态数据成员
}
//普通函数
void show_data(){
    cout << this->data << endl; 
    cout << this->my_data << endl; 
}

private:  
    int data;
static int my_data; 
};

int base::my_data=0;//类外初始化,类中的静态成员

int main()
{
   /*
   base a;
   a.set_data(10086); 
   a.show_data();
    */ 
   base::set_data(10010); //不需要创建对象,直接调用。  简化调用,节省空间
   base::show_data(); //必须创建对象后调用
}

四、类中const成员

const : 修改变量的属性为常量,常量是无法修改的!

特点:

1、类中的常量数据成员,必须要初始化,否则无法定义对象。  

(1)构造函数参数列表中初始化           base(int tmp):data(tmp)

(2)定义常量数据成员的时候初始化)  const int data=100; 

2、初始化后就无法修改 ,且属于类中的数据成员 。

#include <iostream>
using namespace std;

class base
{
public:
    base(int tmp) : data(tmp){ }
    void set_base(){
        // this->data = 100; //常量数据成员无法修改 ?
    }

    void show(){
        cout << this->data << endl;
    }
private:
    const int data = 100;
};

int main()
{
    base tmp(100);

    tmp.show();

    cout << sizeof(base) << endl;
}

五、类中的const 成员函数特点

1、定义常量成员函数必须在后面添加 const 。
    void show() const {} 

2、常量成员函数,无法修改类中的数据成员。   (只能访问,无法修改)
    
3、如果想要修改类中的数据成员,必须添加 mutable 修饰数据成员。

#include <iostream>

using namespace std;

int value = 10086;

class base
{
public:
   //静态成员函数
   static void set_data(int d)
   {
      // base::data = d;  无法访问非静态数据
      value = d; //因为value 存储在数据段 ,是先于 main 函数存在的

      my_data = d; //类中的静态数据成员
   }
   //普通函数
   void show_data()
   {
      cout << this->data << endl;
      cout << this->my_data << endl;
   }

private:
   int data;
   static int my_data;
};

//类外初始化,类中的静态成员
int base::my_data = 0;

int main()
{
   /*
   base a;
   a.set_data(10086);
   a.show_data();
    */

   base::set_data(10010); //不需要创建对象,直接调用。  简化调用,节省空间

   base::show_data(); //必须创建对象后调用
}

六、类中的const 对象特点

1、常量对象,无法修改类中的数据成员 
    const base tmp;
    tmp.data = 10010; //错误的,无法修改。

2·常量对象,无法调用类中的非常量成员函数。 //常量对象的目的就是为了不要修改,类中的数据成员,假设调用非常  量成员函数,还是可以修改这就失去常量对象的作用了。

3、mutable 可以修饰变量,可被修改! 

#include <iostream>
using namespace std;

class base
{
public:
	void set_base(int d) const{
		this->data = d;
	}

	//常量成员函数
	void show() const{
		cout << this->data << endl;
	}
	//修饰为可以修改
	mutable int data = 100;
};

int main()
{

	const base tmp; //定义一个常量对象

	tmp.set_base(123); //利用接口修改数据
	// tmp.show();

	tmp.data = 10010; //直接修改数据
	tmp.show();
}

 七、模板

1、为什么要模板?

答:提高代码的复用性!

例子:

例如:设计一个函数实现两个数据的相加 
C语言: 必须要设计多个函数接口 
 char add_char(char a,char b); 
 float add_float(float a,float b); 
 char * add_str(char *a,char *b); 

C++: 利用函数重载 
 char   add(char a,char b);
 float  add(float a,float b); 
 char * add(char * a,char * b); 

C++ 只是优化了不需要,编写多个不同函数名和调用时,不需要分类型调用。但是还是要写多个函数!
 
C++ 模板: 函数模板 
通用类型 T  
T add(T a,T b);   实现两个数,相加的模板 , T 是一种通用类型,表示任意数据类型。
    //节省代码量 

 2、通用类型的定义

template<typename 通用类名称> 或 template<class 通用类名称>

当一个函数中包含一个通用类型,那么这个函数就是模板函数。

3、模板函数的定义

template<class 通用类名称>
通用类名称 函数名(通用类名称 变量名){
    函数主体 
}

定义一个模板输出不同的数据类型  
template<class T>
T print_func(T value){  
    cout << value; 
} 

例子:

#include <iostream>

using namespace std;
定义一个通用类型T 
template <typename T>

T  print_func(T value){
   cout << value << endl; 
}

int main()
{
    print_func("hello"); //根据传递的数据类型自动转换为 
                         //const char *print_func<const char *>(const char *value)
    print_func(3.14); //自动转换为: double print_func<double>(double value) 
    print_func('S'); //自动转换为: char print_func<char>(char value) 
    print_func(1024);//自动转换为: int print_func<int>(int value) 
 
}

模板函数的特点:

1、模板函数会发生自动类型推导,根据用户传递的参数类型确定 T 通用类型。  

2、一个通用类型只能应用一个函数。     
template<class R>
R swap_data(R &a,R &b)
 //R pf(R value); 错误的,R 使用在上面的函数使用  

3、一个通用类型推导一种数据类型。  
swap_data("hello",100); 错误的,一个通用类型R ,无法推导出两种类型 

八、模板函数与普通函数区别

1、如果模板函数与普通函数实现的功能一致,优先使用普通函数。 

2、如果模板函数的参数匹配度比普通函数高,优先使用模板函数。 

3、普通函数可以发生自动类型转换, 模板函数只能发生自动类推导。 

4、假设想要系统调用模板函数,可以声明多几个通用类型 或 者指定调用模板。 
   (1)声明多个通用类型 
   template <class T,class T1>
   void  pf_func(T a,T1 b)
   (2)指定使用模板 
    //指定使用模板函数,并指定模板类型 
    pf_func<int>(3.14,20);  

5、模板函数也可以重载 

例子:

#include <iostream>
using namespace std;

 普通函数
void  pf_func(int a,int b){
  cout << "普通函数" << endl; 
   输出类型名称 
  cout << typeid(a).name() << endl;  
  cout << a << endl;
  cout << b << endl; 
}

 模板函数 
template <class T>
void  pf_func(T a,T b){
    cout << "模板函数" << endl; 
    cout << typeid(a).name() << endl; 
    cout << a << endl;
    cout << b << endl; 
}

 模板函数的重载
template <class T>
void  pf_func(T a){
    cout << "模板函数" << endl; 
    cout << typeid(a).name() << endl; 
    cout << a << endl;
}

int main()
{
    //指定使用模板函数,并指定模板类型 
    pf_func<int>(3.14,20);
    pf_func(123);
}

九、模板函数的局限性

问题: 对于用户自定义的数据类型,模板函数只能推导,不能操作。

解决方法:

1、重载用户自定义的数据的操作运算符 。

2、编写一个普通函数处理用户自定义数据。

例子:

#include <iostream>
using namespace std;

//自定义一个类型 
class base {
public: 
    base(int d):data(d){}
    void show(){
        cout << data << endl;
    }
private: 
    int data;

//friend bool operator>(base a,base b);
friend base  big_data(base value,base value1);
};

#if 0
重载比较运算符 
bool operator>(base a,base b)
{
   if(a.data > b.data )
   {
       return true;
   }else 
   {
      return false;
   }
}
#endif 

定义一个通用类型T 
template <typename T>
T  big_data(T value,T value1)
{
   if(value > value1)
   {
    return value;
   }else{
    return  value1;
   }
}

重载函数实现 base 的比较 
base  big_data(base value,base value1)
{
    if(value.data > value1.data)
   {
    return value;
   }else{
    return  value1;
   }
}

int main()
{
   
   base tmp(10); 
   base tmp1(20); 

   base max = big_data(tmp,tmp1);  //base big_data<base>(base value, base value1) 
   max.show();

}

十、模板类

1、当一个类包含一个通用类型时,这个类就是模板类。

//定义一个通用类型 
template <class T>
//利用通用类型定义模板类 
class base {
        private: 
        T data;
};

模板类:必须实例化才能使用

base tmp;     //错误的,没有实例化模板,无法定义对象

base<int>  tmp1;  //模板实例化 

模板类作为参数

当一个类是模板类,就无法直接通过类名作为参数传递 。

解决方法:

1、在参数列表中,指定模板类的类型。
void show_base(base<int> tmp) 
2、继续把类型模板化 
template <class T>
void show_base1(base<T> tmp)
3、直接把参数设为模板类型   
template <class T>
void show_base2(T tmp)

 例子:

#include  <iostream>
using namespace std;

定义一个通用类型 
template <class T>

利用通用类型定义模板类
class base {
public: 
base(T value):data(value){} 
void show(){
    cout << data << endl; 
}
T data;
};

1.指导模板类的类型 
void show_base(base<int> tmp)	如果数据是私有成员,可以用友元访问
{
   cout << tmp.data << endl; 
}

2.继续把类型模板化  
template <class T>	
void show_base1(base<T> tmp)	如果数据是私有成员,不能友元来访问
{
    cout << tmp.data << endl; 
}


3.把参数设置为模板类型  
template <class T>
void show_base2(T tmp)			如果数据是私有成员,不能友元来访问
{
    cout << tmp.data << endl; 
}


int main()
{
   base<int>  tmp(10086);
   show_base(tmp);
   show_base1(tmp);
   show_base2(tmp);
}

十一、模板类的成员函数类外编写

#include  <iostream>
using namespace std;

template <class T>
class base
{
public: 
    void set_base(T value);
    void show_base();
private: 
    T  data;
};

类外编写base 模板类的成员函数 
template <class T>
void base<T>::set_base(T value){
   this->data = value; 
}

template <class T>
void base<T>::show_base(){
   cout  << this->data << endl;
}


int main()
{
   定义一个模板类对象 
   base<int>  tmp; 

   tmp.set_base(10086); 

   tmp.show_base();

}

模板类的成员函数,最好在类内编写,比较简单。

十二、模板类的继承

问题:模板类是无法直接派生

解决方法:

1、在派生时指定模板类的类型  
class  base_a : public  base<int> 
    
2、继续把派生类设置为模板类  
template <class T>
class  base_b:public base<T>

例子:

#include <iostream>
using namespace std;

定一个模板类
template <class T>
class  base {
public: 
    base(T v):data(v){}
    void show(){cout << data << endl;}
private: 
    T  data;
};

//派生类  -> 已经实例化了,派生类不再是模板类
class  base_a : public  base<int> {
public:
    base_a(int value):base(value){}
}; 

继续把派生类设置为模板类  
template <class T>
class  base_b:public base<T>{
public: 
    base_b(T value):base<T>(value){}
};

int main()
{
   base_a tmp(100);
   tmp.show(); 

   base_b<int> tmp1(200);
   tmp1.show(); 
}

总结:

知晓模板的本质是为了更好的理解STL库,因为STL库是一个个封装好的模板,只需调用即可。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值