C++基础11:模板与命名空间

news2024/9/24 15:28:55

此专栏为移动机器人知识体系下的编程语言中的 C {\rm C} C++从入门到深入的专栏,参考书籍:《深入浅出 C {\rm C} C++》(马晓锐)和《从 C {\rm C} C C {\rm C} C++精通面向对象编程》(曾凡锋等)。



10.模板与命名空间
10.1 模板简述
  • 模板使函数和类的处理对象参数化,使代码具有通用性;

  • C {\rm C} C++程序的组成单位是函数和类,因此,模板分为函数模板 ( f u n c t i o n   t e m p l a t e ) ({\rm function\ template}) (function template)和类模板 ( c l a s s   t e m p l a t e ) ({\rm class\ template}) (class template);定义模板后,可以处理不同的数据类型,不必显式定义针对不同数据类型的函数或类;

  • 模板、函数模板、类模板与对象间的关系如下:

    15

  • 模板可以最大限度地实现代码重用,使代码精简;

10.2 函数模板
  • 函数模板是一类可以被实例化的特殊函数,通过模板可以操作通用类型的数据,函数模板处理的数据类型是通过参数来体现,在函数模板实例化的过程中,才将这些参数具体化为一种特定的数据类型,因此,在定义函数时不用为每种数据类型都编写重复的相似代码;模板中表示数据类型的参数称为模板参数,这是一种特殊的参数,能传递一种数据类型;

  • 声明函数模板参数类型的语法格式:

    // 声明格式1:
    template <class 类型标识符> 返回类型 函数名(函数形参表);
    
    // 声明格式2:
    template <typename 类型标识符> 返回类型 函数名(函数形参表);
    
    • t e m p l a t e {\rm template} template是声明模板的关键字,表示声明一个模板;
    • t e m p l a t e {\rm template} template关键字后是用尖括号’<>'括起来的类型参数表,类型参数表中包含一个或多个由逗号分隔的类型参数项,每一项由关键字 c l a s s {\rm class} class和用户命名的标识符组成,此标识符为类型参数,不是一种数据类型,可以同一般数据类型一样使用在函数的任何地方;
  • 调用函数模板的语法格式:

    函数名<具体类型>(参数表);
    
  • 在调用函数模板时,<具体类型>可以省略,由系统自动判定;当<具体类型>不省略时,为显式实例化,当<具体类型>省略时,为隐式实例化;

  • 函数模板接收参数类型问题:

    // 定义一个返回两个对象中较大对象的函数模板;
    // 下面的函数模板只能接收相同参数,不能接收两个不同的参数;
    // 因为只包含了一种类型的模板参数typename TheType;
    template <typename TheType>
    TheType GetMax(TheType a,TheType b)
    {
        return (a>b?a:b);
    }
    
    // 下面的函数模板可以接收两个不同类型的参数;
    template <typename TheType1,typename TheType2>
    TheType1 GetMax(TheType1 a,TheType2 b)
    {
        return (a>b?a:b);
    }
    
  • 函数模板实例:定义一个操作数组的函数模板,完成遍历数组输出元素的功能 ( e x a m p l e 10 _ 1. c p p ) ({\rm example10\_1.cpp}) (example10_1.cpp)

    /**
     * 作者:罗思维
     * 时间:2024/03/24
     * 描述:定义一个操作数组的函数模板,完成遍历数组输出元素的功能
     */
    #include <iostream>
    #include <string>
    
    using namespace std;
    
    // 定义函数模板;
    template <class T>
    void printArray(const T *array, const int count) {
    	for (int i = 0; i < count; i++) {
    		cout << array[i] << " ";
    	}
    	cout << endl;
    }
    
    int main() {
    	int nArray[10] = {10, 20, 30, 40, 50, 60, 70, 80, 90, 100};
    	char cArray[] = {'W', 'E', 'L', 'C', 'O', 'M', 'E'};
    
    	// 调用函数模板输出整型数组和字符数组中元素;
    	printArray(nArray, sizeof(nArray) / sizeof(int));
    	printArray(cArray, sizeof(cArray) / sizeof(char));
    	return 0;
    }
    
  • 模板函数可以像普通函数一样被重载,实例如下 ( e x a m p l e 10 _ 2. c p p ) ({\rm example10\_2.cpp}) (example10_2.cpp)

    /**
     * 作者:罗思维
     * 时间:2024/03/24
     * 描述:模板函数重载。
     */
    #include <iostream>
    #include <string.h>
    
    using namespace std;
    
    // 定义函数模板;
    template <typename TheType>
    TheType GetMax(TheType a, TheType b) {
    	return (a > b ? a : b);
    }
    
    // 重载函数模板,使函数模板支持字符串的处理;
    char* GetMax(char* a, char* b) {
    	return (strcmp(a, b) > 0 ? a : b);
    }
    
    int main() {
    	int nNumber1 = 10, nNumber2 = 20;
    	float fNumber1 = 13.14, fNumber2 = 5.20;
    
    	char a = 'L', b = 'C';
    	char *p1 = (char*)"C++";
    	char *p2 = (char*)"Python";
    
    	cout << "GetMax(10,20):" << GetMax(nNumber1, nNumber2) << endl;
    	cout << "GetMax(13.14,5.20):" << GetMax(fNumber1, fNumber2) << endl;
    
    	cout << "GetMax('L','C'):" << GetMax(a, b) << endl;
    	cout << "GetMax('C++','Python'):" << GetMax(p1, p2) << endl;
    
    	return 0;
    }
    
10.3 类模板
  • 类模板的作用:将类所处理的对象类型参数化,它使得类中的某些数据成员的参数和返回值能取任意数据类型;

  • 类模板定义的语法格式:

    template <类型参数表>
    class 类名
    {
        // 类体
    };
    
    • t e m p l a t e {\rm template} template:声明模板的关键字,表示声明一个模板类;
    • <类型参数表>中包含一个或多个类型参数项,每一项由关键字 c l a s s {\rm class} class和一个用户自定义的标识符组成,标识符为类型参数;
    • 使用类模板时,先将其实例化,即用实际的数据类型代替类型参数;
    • 当类模板中的成员函数在类定义体外定义时,必须被定义为一个函数模板的形式;
  • 类模板实战项目 ( c l a s s T e m p l a t e ) ({\rm classTemplate}) (classTemplate)

    • 项目需求:定义一个简单通用数组类模板,实现对一般数据类型数组的操作;

    • C A r r a y {\rm CArray} CArray类定义头文件 ( C A r r a y . h ) ({\rm CArray.h}) (CArray.h)

      /**
       * 作者:罗思维
       * 时间:2024/03/25
       * 描述:CArray类定义头文件。 
       */
      #pragma once
      #include <iostream>
      #include <iomanip>
      #include <string.h>
      
      using namespace std;
      
      const int MIN_SIZE = 30;
      
      // 定义模板类 
      template <class T>
      class CArray {								// 数组类; 
      	protected:
      		T* m_pArray;						// 数组指针; 
      		int m_nSize;						// 数组元素个数; 
      	public:
      		CArray(int nSize, T Initial);		// 构造函数,初始化数组; 
      		~CArray() {							// 析构函数,释放内存; 
      			delete[] m_pArray;
      		};
      		T& operator[] (int nIndex) {		// 重载数组下标运算符; 
      			return m_pArray[nIndex];
      		};
      		void Show(const int nNumElems);		// 输出前nNumElems个元素; 
      		void Sort(int nNumElems);			// 将前nNumElems个元素进行排序; 
      };
      
      template <class T>
      CArray<T>::CArray(int nSize, T InitVal) {
      	m_nSize = (nSize > 1) ? nSize : 1;		// 保证nSize不小于1; 
      	m_pArray = new T[m_nSize];
      	for (int i = 0; i < m_nSize; i++) {
      		m_pArray[i] = InitVal;				// 将元素全部初始化为InitVal; 
      	}
      }
      
      template <class T>
      void CArray<T>::Show(const int nNumElems) {
      	for (int i = 0; i < nNumElems; i++) {
      		cout << m_pArray[i] << ' ';
      	}
      }
      
      template <class T>
      void CArray<T>::Sort(int nNumElems) {		// 对元素进行排序; 
      	int nOffset = nNumElems;
      	bool bSorted;
      	if (nNumElems < 2) {
      		return;
      	}
      	do {
      		nOffset = (nOffset * 8) / 11;
      		nOffset = (nOffset < 1) ? 1 : nOffset;
      		bSorted = true;
      		for (int i = 0, j = nOffset; i < (nNumElems - nOffset); i++, j++) {
      			if (m_pArray[i] > m_pArray[j]) {
      				T nSwap = m_pArray[i];
      				m_pArray[i] = m_pArray[j];
      				m_pArray[j] = nSwap;
      				bSorted = false;
      			}
      		}
      	} while (!bSorted || nOffset != 1);
      }
      
    • C M y S t r i n g {\rm CMyString} CMyString类定义头文件 ( C M y S t r i n g . h ) ({\rm CMyString.h}) (CMyString.h)

      /**
       * 作者:罗思维
       * 时间:2024/03/25
       * 描述:CMyString类定义头文件。 
       */
      #pragma once
      #include "CArray.h"
      
      // 定义字符串类; 
      class CMyString {
      	protected:
      		char* m_pszString;					// 字符串指针; 
      		int m_nSize;						// 字符串中的字符个数; 
      	public:
      		CMyString(int nSize = MIN_SIZE) {
      			m_pszString = new char[m_nSize = nSize];
      		};
      		CMyString(const CMyString& CString);
      		CMyString(const char* pszString);
      		CMyString(const char cChar);
      		~CMyString() {
      			delete[] m_pszString;
      		};
      		int getLen() {
      			return strlen(m_pszString);
      		};
      		int getMaxLen() {
      			return m_nSize;
      		};
      
      		// 重载运算符= 
      		CMyString& operator=(const CMyString& aString);
      		CMyString& operator=(const char* pszString);
      		CMyString& operator=(const char cChar);
      
      		// 重载运算符> 
      		friend operator > (CMyString& aString1, CMyString& aString2) {
      			return (strcmp(aString1.m_pszString, aString2.m_pszString) > 0) ? 1 : 0;
      		}
      		friend ostream& operator << (ostream& os, CMyString& aString);
      };
      
    • C M y S t r i n g {\rm CMyString} CMyString类实现文件 ( C M y S t r i n g . c p p ) ({\rm CMyString.cpp}) (CMyString.cpp)

      /**
       * 作者:罗思维
       * 时间:2024/03/25
       * 描述:CArray类实现文件。 
       */
      #include "CMyString.h"
      
      CMyString::CMyString(const CMyString &aString) {
      	m_pszString = new char[m_nSize = aString.m_nSize];
      	strcpy(m_pszString, aString.m_pszString);
      }
      
      CMyString::CMyString(const char *pszString) {
      	m_pszString = new char[m_nSize = strlen(pszString) + 1];
      	strcpy(m_pszString, pszString);
      }
      
      CMyString::CMyString(const char cChar) {
      	m_pszString = new char[m_nSize = MIN_SIZE];
      	m_pszString[0] = cChar;
      	m_pszString[1] = '\0';
      }
      
      CMyString &CMyString::operator=(const CMyString &aString) {
      	// 检查是否有足够的空间进行字符串的复制; 
      	if (strlen(aString.m_pszString) < unsigned(m_nSize)) {
      		strcpy(m_pszString, aString.m_pszString);
      	} else {
      		strncpy(m_pszString, aString.m_pszString, m_nSize - 1);
      	}
      
      	return *this;
      }
      
      CMyString &CMyString::operator=(const char *pszString) {
      	if (strlen(pszString) < unsigned(m_nSize)) {
      		strcpy(m_pszString, pszString);
      	} else {
      		strncpy(m_pszString, pszString, m_nSize - 1);
      	}
      
      	return *this;
      }
      
      CMyString &CMyString::operator=(const char cChar) {
      	if (m_nSize > 1) {
      		m_pszString[0] = cChar;
      		m_pszString[1] = '\0';
      	}
      
      	return *this;
      }
      
      // 输出对象重载; 
      ostream &operator << (ostream &os, CMyString &aString) {
      	os << aString.m_pszString;
      	return os;
      }
      
    • 程序主文件 ( m a i n . c p p ) ({\rm main.cpp}) (main.cpp)

      /**
       * 作者:罗思维
       * 时间:2024/03/25
       * 描述:程序主文件。 
       */
      #include <iostream>
      #include "CMyString.h"
      
      using namespace std;
      
      int main() {
      	const int MAX_ELEMS = 10;
      	int nArr[MAX_ELEMS] = {10, 20, 40, 50, 60, 90, 80, 70, 30, 100};
      	char cArr[MAX_ELEMS] = {'C', 'W', 'r', 'Y', 'k', 'J', 'X', 'Z', 'y', 's'};
      
      	CArray<int> IntegerArray(MAX_ELEMS, 0);			// 用int类型实例化通用数组类模板;
      	CArray<char> CharArray(MAX_ELEMS, ' ');			// 用char类型实例化通用数组类模板;
      	CArray<CMyString> StringArray(MAX_ELEMS, " ");	// 用自定义类型CMyString实例化通用数组类模板;
      
      	for (int i = 0; i < MAX_ELEMS; i++) {
      		IntegerArray[i] = nArr[i];
      	}
      
      	for (int i = 0; i < MAX_ELEMS; i++) {
      		CharArray[i] = cArr[i];
      	}
      
      	StringArray[0] = "GuangDong";
      	StringArray[1] = "BeiJing";
      	StringArray[2] = "HuBei";
      	StringArray[3] = "GuiZhou";
      	StringArray[4] = "GuangXi";
      	StringArray[5] = "HuNan";
      	StringArray[6] = "ShanDong";
      	StringArray[7] = "ShanXi";
      	StringArray[8] = "JiangSu";
      	StringArray[9] = "ZheJiang";
      
      	// 输出IntegerArray排序前后的内容;
      	cout << "Unsorted array is:" << endl;
      	IntegerArray.Show(MAX_ELEMS);
      	IntegerArray.Sort(MAX_ELEMS);
      	cout << "\nSorted array is:" << endl;
      	IntegerArray.Show(MAX_ELEMS);
      	cout << endl;
      
      	// 输出CharArray排序前后的内容;
      	cout << "Unsorted array is:" << endl;
      	CharArray.Show(MAX_ELEMS);
      	CharArray.Sort(MAX_ELEMS);
      	cout << "\nSorted array is:" << endl;
      	CharArray.Show(MAX_ELEMS);
      	cout << endl;
      
      	// 输出StringArray排序前后的内容;
      	cout << "\nUnsorted array is:" << endl;
      	StringArray.Show(MAX_ELEMS);
      	StringArray.Sort(MAX_ELEMS);
      	cout << "\nSorted array is:" << endl;
      	StringArray.Show(MAX_ELEMS);;
      
      	return 0;
      }
      
10.4 命名空间
  • 命名空间是 A N S I   C {\rm ANSI\ C} ANSI C++引入的可以由用户命名的作用域,用来处理程序中常见的同名冲突;

  • C {\rm C} C++中的作用域有文件作用域、函数作用域、复合语句作用域和类作用域等,在不同的作用域中,定义具有相同名称的变量是合法的;

  • 在文件中可以定义全局变量,作用域是整个程序,在同一个作用域中不应该出现两个或多个同名的实体;

  • 在大型软件开发中,一般程序分模块完成,在各模块中可能会产生同名的实体,从而产生命名冲突;

  • 如果引用标准库、第三方库、自定义库中包含与程序中定义的全局实体同名的实体,或不同库之间有同名的实体,则编译时出现命名冲突,称为全局命名空间污染 ( g l o b a l   n a m e s p a c e   p o l l u t i o n ) ({\rm global\ namespace\ pollution}) (global namespace pollution)

  • 命名空间是由开发者命名的一个作用域区域,这些区域称为空间域,开发者可以根据需要指定一些有名称的空间域,把自定义的实体放在这个空间域中,保证使其与外界分离,这样可以使空间域内部实体不会与外界产生冲突;

  • 命名空间定义的语法格式:

    namespace <命名空间名>
    {
        ...;	// 命名空间实体;
    }
    
    • n a m e s p a c e {\rm namespace} namespace:定义命名空间的关键字;
    • <命名空间名>:用户指定的命名空间的名称;
    • 大括号内是声明块,在其中声明的实体称为命名空间成员 ( n a m e s p a c e   m e m b e r ) ({\rm namespace\ member}) (namespace member),命名空间成员可以包含变量、常量、结构体、类、模板、命名空间等;
  • 命名空间举例:

    namespace myns
    {
        int a;
        char c;
    }
    
    • 在程序中使用变量 a 、 c {\rm a、c} ac,需要加上命名空间名和作用域限定符" : : :: ::",如: m y n s : : a 、 m y n s : : c {\rm myns::a、myns::c} myns::amyns::c,此用法称为命名空间限定 ( q u a l i f i e d ) ({\rm qualified}) (qualified) m y n s : : a {\rm myns::a} myns::a称为被限定名 ( q u a l i f i e d   n a m e ) ({\rm qualified\ name}) (qualified name)
  • 程序开发过程中,可以根据实际情况定义多个命名空间,把不同的库中的实体放到不同的命名空间中,即用不同的命名空间把不同的实体隐藏起来;

  • 对命名空间成员引用的语法格式:

    命名空间::命名空间成员名
    
  • 命名空间的几种使用方法:

    • 定义命名空间后,可以为其起一个别名:

      // 声明命名空间,名为:NameSpaceGraduateStudent;
      namespace NameSpaceGraduateStudent
      {
          ...;
      }
      
      // 给命名空间起别名;
      namespace NSGS=NameSpaceGraduateStudent;
      
    • 使用 u s i n g {\rm using} using引入命名空间中的成员, u s i n g {\rm using} using的作用是引入命名空间或命名空间中的成员,其后面必须是由命名空间限定的名称;

      // 用using引入命名空间中的成员;
      // 引入后可以直接引用CStudent即可;
      using Stu::CStudent;
      
      // 等价关系;
      Stu::CStudent student ("Willard")	等价于		CStudent student ("Willard")
      
    • 使用 u s i n g   n a m e s p a c e {\rm using\ namespace} using namespace引入命名空间,可以一次性引入命名空间的全部成员,语法格式:

      using namespace 命名空间名;
      
    • 无名的命名空间,在其他文件中无法使用,只能在本文件的作用域有效,语法格式:

      namespace
      {
          // 定义命名空间名;
          void func()
          {
              ...;
          }
      }
      
  • 标准命名空间 s t d {\rm std} std,在程序中没有引入标准命名空间时,要使用其中的成员,则使用 s t d {\rm std} std来进行限定;

  • C {\rm C} C++头文件的作用:为用户提供调用其实现的外部接口;

10.5 实战

项目需求

约瑟夫 ( J o s e p h u s ) ({\rm Josephus}) (Josephus)问题:假设有 n n n个小孩做成一个环,从第一个小孩开始数数,如果数到第 m m m个小孩,则该小孩离开,问最后留下的小孩是第几个小孩?

问题分析

如果总共有 6 6 6个小孩,围成一圈,从第一个小孩开始,每次数 2 2 2个小孩,则游戏情况过程:

小孩序号: 1 、 2 、 3 、 4 、 5 、 6 1、2、3、4、5、6 123456

离开小孩序号: 2 、 4 、 6 、 3 、 1 2、4、6、3、1 24631

则获胜小孩序号为: 5 5 5

代码实现 ( J o s e p h u s ) ({\rm Josephus}) (Josephus)

  • J o s e p h u s R i n g . h {\rm JosephusRing.h} JosephusRing.h代码:

    /**
     * 作者:罗思维
     * 时间:2024/03/26
     * 描述:JosephusRing类定义头文件; 
     */
    #pragma once
    #include <iostream>
    #include <iterator>			// iterator:迭代器 
    #include <list>				// list是一个容器,其结构为双向链表;
    
    using namespace std;
    
    template <class Type>
    class JosephusRing {
    		list <Type> lst;
    
    	public:
    		class iterator;
    		friend class iterator;
    		class iterator: public std::iterator<std::bidirectional_iterator_tag, Type, ptrdiff_t> {
    				typename list<Type>::iterator it;
    				list<Type>* r;
    			public:
    				iterator(list<Type>& lst, const typename list<Type>::iterator& i): it(i), r(&lst) {};
    				bool operator==(const iterator& x) const {
    					return it == x.it;
    				};
    				bool operator!=(const iterator& x) const {
    					return !(*this == x);
    				};
    				typename list<Type>::reference operator*() const {
    					return *it;
    				};
    				iterator& operator++() {
    					++it;
    					if (it == r->end()) {
    						it = r->begin();
    					}
    					return *this;
    				};
    				iterator operator++(int) {
    					iterator tmp = *this;
    					++* this;
    					return tmp;
    				};
    				iterator& operator--() {
    					if (it == r->begin()) {
    						it = r->end();
    					}
    					--it;
    					return *this;
    				};
    				iterator operator--(int) {
    					iterator tmp = *this;
    					--*this;
    					return tmp;
    				};
    				iterator insert(const Type& x) {
    					return iterator(*r, r->insert(it, x));
    				};
    				iterator erase() {
    					return iterator(*r, r->erase(it));
    				};
    		};
    
    		void push_back(const Type& x) {
    			lst.push_back(x);
    		};
    
    		iterator begin() {
    			return iterator(lst, lst.begin());
    		};
    
    		int size() {
    			return lst.size();
    		}
    };
    
  • 程序主文件 ( m a i n . c p p ) ({\rm main.cpp}) (main.cpp)

    /**
     * 作者:罗思维
     * 时间:2024/03/26
     * 描述:程序主文件。 
     */
    #include "JosephusRing.h"
    
    int main() {
    	int n, m;
    	cout << "请输入小孩总数:";
    	cin >> n;
    
    	cout << "每次数的孩子数:";
    	cin >> m;
    
    	JosephusRing<int> Josephus;
    	for (int i = 1; i <= n; i++) {
    		Josephus.push_back(i);
    	}
    
    	JosephusRing<int>::iterator tmp = Josephus.begin();
    	JosephusRing<int>::iterator it = tmp;
    
    	for (int index = 0; index < n - 1; index++) {
    		it = tmp;
    		for (int j = 0; j < m - 1; j++) {
    			it++;
    			tmp++;
    		}
    		tmp++;
    		cout << "离开的孩子:" << *it << endl;
    		it.erase();
    	}
    	it = Josephus.begin();
    
    	cout << "最后剩下的孩子:" << *it << endl;
    
    	return 0;
    }
    

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1551958.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Hbase 王者荣耀数据表 HBase常用Shell命令

大数据课本&#xff1a; HBase常用Shell命令 在使用具体的Shell命令操作HBase数据之前&#xff0c;需要首先启动Hadoop&#xff0c;然后再启动HBase&#xff0c;并且启动HBase Shell&#xff0c;进入Shell命令提示符状态&#xff0c;具体命令如下&#xff1a; $ cd /usr/local…

13.软件测试过程与管理

重点&#xff1a; 软件测试的成本管理&#xff1a;区分一致性成本和非一致性成本&#xff1b;根据题干描述计算质量成本、投资回报率&#xff1b; DDP&#xff1a;缺陷探测率的计算&#xff1b;下午题考的频率高&#xff1b; 主要议题&#xff1a; 1.软件测试过程 2.软件测试…

教育建筑智慧能源管理平台解决方案【新型电力系统下的绿色校园能源管理平台】

一、行业特点 1.建筑类型多&#xff1a;集教学、科研、生活于一体&#xff0c;占地面积大&#xff0c;建筑类型多&#xff0c;功能划分复杂。 2.供电可靠性要求高&#xff1a;教育建筑中的高层建筑、图书馆、实验楼等特级和一级负荷比较多&#xff0c;一旦发生故障会危及生命…

【IP 组播】PIM-SM

目录 原理概述 实验目的 实验内容 实验拓扑 1.基本配置 2.配置IGP 3.配置PIM-SM 4.用户端DR与组播源端DR 5.从RPT切换到SPT 6.配置PIM-Silent接口 原理概述 PIM-SM 是一种基于Group-Shared Tree 的组播路由协议&#xff0c;与 PIM-DM 不同&#xff0c;它适合于组播组成…

C++模板类和模板函数

模板类 #include<bits/stdc.h> using namespace std; template<typename T> class People{public:People(T name):name_(name){}protected:T name_; }; class A:public People<string>{public:A(string name): People(name){}void print(){std::cout<<…

启动性能优化

一、应用启动慢的原因 1.在主线程执行了太多耗时的操作&#xff0c;比如加载数据&#xff0c;或者初始化三方库等等&#xff0c;导致在Application的oncreate或者Activity的oncreate方法中耗时太久 2.布局嵌套太深&#xff0c;或者一些不会立即使用的布局也在一开始一起加载到…

tomcat配置静态资源后无法正常访问

目录 一、场景二、配置三、访问异常四、排查五、原因六、解决 一、场景 1、将前端文件存在到指定目录 2、在tomcat配置静态资源 3、配置后无法正常访问到前端文件 二、配置 1、tomcat配置 2、静态资源 三、访问异常 四、排查 可以ping通&#xff0c;但是访问不了3080端口 …

4G CAT.1单灯控制器 计讯物联TL112

传统的照明控制方式往往需要通过开关进行操作&#xff0c;而单灯控制器的出现改变了这一局面。计讯物联单灯控制器TL112&#xff0c;一种基于无线通信技术的智能照明控制设备&#xff0c;可通过管理中心平台、pc电脑端、手机端等多方式&#xff0c;实现对路灯的智能控制&#x…

Springboot整合瀚高

需要下载highgo驱动,然后将jar包打入进自己本地maven中 下载地址: highgi6.2.4 1.打开jar包所在的文件&#xff0c;然后在该文件夹中打开命令窗口&#xff08;或者先打开命令窗口&#xff0c;然后cd到jar所在文件夹&#xff09; install-file -Dfile&#xff1a;jar包名Dart…

SQL Server事务复制操作出现的错误 进程无法在“xxx”上执行sp_replcmds

SQL Server事务复制操作出现的错误 进程无法在“xxx”上执行“sp_replcmds” 无法作为数据库主体执行&#xff0c;因为主体 "dbo" 不存在、无法模拟这种类型的主体&#xff0c;或您没有所需的权限

机器学习——元学习

元学习&#xff08;Meta Learning&#xff09;是一种机器学习方法&#xff0c;旨在使模型能够学习如何学习。它涉及到在学习过程中自动化地学习和优化学习算法或模型的能力。元学习的目标是使模型能够从有限的训练样本中快速适应新任务或新环境。 在传统的机器学习中&#xff…

Linux 反引号、单引号以及双引号的区别

1.单引号—— 单引号中所有的字符包括特殊字符&#xff08;$,,和\&#xff09;都将解释成字符本身而成为普通字符。它不会解析任何变量&#xff0c;元字符&#xff0c;通配符&#xff0c;转义符&#xff0c;只被当作字符串处理。 2.双引号——" 双引号&#xff0c;除了$,…

遥感卫星影像质量评价指标汇总

1. 主观评价方法 以人为图像的评价者&#xff0c;根据自己的评价尺度和经验对图像质量进行评价。 2. 客观评价方法 1)均方差 2)信噪比 主要用来评价影像经压缩、传输、增强等处理前后的质量变化情况&#xff0c;其本质与均方差类似。 3)方差 反映了图像各个像元灰度相对…

游戏本笔记本更换@添加内存条实操示例@DDR5内存条

文章目录 添加内存条的意义准备工具设备拔出电源适配器并关机&#x1f47a;样机 内存条上的金手指安装过程Notes 安装后开机初次开机速度屏幕显示分辨率和闪烁问题检查安装后的效果 添加内存条的意义 参考双通道内存DDR5多通道内存-CSDN博客 准备工具 准备一个质量差不多的螺…

【正版特惠】IDM 永久授权 优惠低至109元!

尽管小编有修改版IDM&#xff0c;但是由于软件太好用了&#xff0c;很多同学干脆就直接购买了正版&#xff0c;现在正版也不贵&#xff0c;并且授权码绑定自己的邮箱&#xff0c;直接官方下载激活&#xff0c;无需其他的绿化修改之类的操作&#xff0c;不喜欢那么麻烦的&#x…

python知识点总结(十)

python知识点总结十 1、装饰器的理解、并实现一个计时器记录执行性能&#xff0c;并且将执行结果写入日志文件中2、队列和栈的区别&#xff0c;并且用python实现3、设计实现遍历目录与子目录4、CPU处理进程最慢的情况通常发生在以下几种情况下&#xff1a;5、CPU处理线程最慢的…

【嵌入式机器学习开发实战】(七)—— 政安晨:通过ARM-Linux掌握基本技能【环境准备:树莓派】

ARM-Linux是一种针对ARM架构的操作系统&#xff0c;它的设计目标是在低功耗、低成本的硬件平台上运行。ARM-Linux可以运行在多种ARM处理器上&#xff0c;包括树莓派。 树莓派&#xff08;Raspberry Pi&#xff09;是一款基于ARM架构的单板计算机&#xff0c;由英国的树莓派基金…

46.continue语句

目录 一.continue语句 二.视频教程 一.continue语句 continue语句的作用和break语句很像&#xff0c;break语句会跳出当前循环&#xff0c;而continue语句则是跳出本次循环&#xff0c;继续执行下一次循环。 举个例子&#xff1a; #include <stdio.h>void main(void)…

HarmonyOS实战开发-实现带有卡片的电影应用

介绍 本篇Codelab基于元服务卡片的能力&#xff0c;实现带有卡片的电影应用&#xff0c;介绍卡片的开发过程和生命周期实现。需要完成以下功能&#xff1a; 元服务卡片&#xff0c;用于在桌面上添加2x2或2x4规格元服务卡片。关系型数据库&#xff0c;用于创建、查询、添加、删…

LLMOps与传统的MLOps有何不同?

引言&#xff1a; 随着AI技术的日新月异&#xff0c;大语言模型&#xff08;LLM&#xff09;已经成为推动企业增长和创新的关键驱动力。然而&#xff0c;在实际应用中&#xff0c;要想充分发挥大模型的潜力&#xff0c;还需要克服众多挑战&#xff0c;包括语料的精准标注与处理…