C++模板基础2——定义类模板

类模板

类模板是用来生成类的蓝图的。

与函数模板的不同之处是,编译器不能为类模板推断模极参数类型。

如我们已经多次看到的,为了使用类模板,我们必须在模板名后的尖括号中提供额外信息——用来代替模板参数的模板实参列表。

定义类模板

类模板的格式如下所示:

template <typename T>
class ClassName {// 类成员和函数声明与定义
};

其中,template <typename T> 表示该类是一个模板类,T 是一个占位符类型,可以在类内部使用。ClassName 是模板类的名称。

我们举个例子

#include <iostream>  // 类模板定义  
template <typename T>  
class MyClass {  
public:  MyClass(T value) : value_(value) {}  void setValue(T value) {  value_ = value;  }  T getValue() const {  return value_;  }  void printValue() const {  std::cout << "Value: " << value_ << std::endl;  }  private:  T value_;  
};  int main() {  // 使用int类型的类模板实例化对象  MyClass<int> intObject(42);  intObject.printValue();  // 输出: Value: 42  // 修改整数值并打印  intObject.setValue(100);  intObject.printValue();  // 输出: Value: 100  // 使用std::string类型的类模板实例化对象  MyClass<std::string> stringObject("Hello, Templates!");  stringObject.printValue();  // 输出: Value: Hello, Templates!  // 修改字符串值并打印  stringObject.setValue("New String Value");  stringObject.printValue();  // 输出: Value: New String Value  return 0;  
}

在这个例子中,我们定义了一个简单的类模板MyClass,它接受一个类型参数T。类内部有一个私有成员变量value_,其类型为T。类中提供了构造函数来初始化value_,以及setValuegetValue成员函数来修改和获取value_的值。此外,还有一个printValue成员函数来打印value_的值。

main函数中,我们使用intstd::string两种类型分别实例化了MyClass,展示了如何使用类模板来创建和操作不同类型的对象。通过这种方式,我们可以很容易地为多种数据类型重用相同的类定义,提高了代码的灵活性和可重用性。 

实例化类模板

当我们想要创建一个特定类型的MyClass对象时,我们需要提供一个具体的类型来替换模板参数T。这个过程就是实例化。

例如,如果我们想要一个整数类型的MyClass对象,我们可以这样实例化:

MyClass<int> intObject(42);

在这里,int就是我们提供的具体类型,它替换了类模板中的T。编译器会生成一个新的类,这个类是为int类型专门定制的MyClass

MyClass<std::string> stringObject("Hello, Templates!");

此时,std::string替换了模板中的T,编译器会生成另一个专门为std::string类型定制的MyClass

编译器的工作

在编译时,当编译器遇到类模板的实例化请求,它会做以下几件事情:

  1. 替换模板中的所有T为提供的实际类型(如intstd::string)。
  2. 生成一个新的类定义,这个定义是专门为提供的类型创建的。
  3. 编译这个新生成的类定义,就像它是一个普通的类一样。
  4. 为新类型生成相应的成员函数、构造函数、析构函数等。

生成的对象

一旦类模板被实例化,我们就可以像使用普通类一样使用这个新生成的类。例如,我们可以调用其成员函数,访问其成员变量等。

 总之,实例化就是将泛型转变为具体类型,生成对应版本代码的过程

在模板作用域中引用模板类型

为了阅读模板类代码,应该记住类模板的名字不是一个类型名。

类模板用来实例化类型,而一个实例化的类型总是包含模板参数的。

可能令人迷惑的是,一个类模板中的代码如果使用了另外一个模板,通常不将一个实际类型(或值)的名字用作其模板实参。

相反的,我们通常将模板自己的参数当作被使用模板的实参。

这些描述涉及到了模板的嵌套使用,也就是说,在一个模板类内部使用了另一个模板,并且使用当前模板的参数作为内部模板的参数。

下面是一个例子来说明这个概念:

#include <vector>
#include <iostream>// 定义一个模板类A,它有一个模板参数T
template <typename T>
class A {
public:std::vector<T> vec;  // 使用模板参数T实例化std::vectorvoid printVec() {for (const auto& elem : vec) {std::cout << elem << " ";}std::cout << std::endl;}
};// 定义一个模板类B,它有两个模板参数:一个是类型参数U,另一个是类模板参数A<T>
template <typename U, typename T>
class B {
public:A<U> a_obj;  // 使用外部模板参数U实例化类模板Avoid addElement(U elem) {a_obj.vec.push_back(elem);}void printVecB() {a_obj.printVec();}
};int main() {// 实例化模板类B,其中U为int,T也为int(用于实例化A<int>)B<int, int> b_obj;b_obj.addElement(10);b_obj.addElement(20);b_obj.addElement(30);b_obj.printVecB();  // 输出:10 20 30 return 0;
}

在这个例子中,A<T> 是一个模板类,它有一个 std::vector<T> 成员。B<U, T> 是另一个模板类,它有一个 A<U> 类型的成员。在 B<U, T> 类模板中,我们使用了外部模板参数 U 来实例化 A<T>,这就是“将模板自己的参数当作被使用模板的实参”的一个例子。

在 main 函数中,我们实例化了 B<int, int>,这意味着我们创建了一个包含 A<int> 成员的 B 类实例。这就是类模板实例化的一个具体例子,其中模板参数被实际类型(在这个例子中是 int)所替代。

类模板的成员函数

与其他任何类相同,我们既可以在类模板内部,也可以在类模板外部为其定义成员函数,且定义在类模板内的成员函数被隐式声明为内联函数。

类模板的成员函数本身是一个普通函数。但是,类模板的每个实例都有其自己版本的成员函数。

因此,类模板的成员函数具有和模板相同的模板参数。

因而,定义在类模板之外的成员函数就必须以关键字template开始,后接类模板参数列表。

与往常一样,当我们在类外定义一个成员时,必须说明成员属于哪个类。而且,从一个模板生成的类的名字中必须包含其模板实参。当我们定义一个成员函数时,模板实参与模板形参相同。

// 声明类模板
template<typename T>
class MyClass {
public:MyClass(T value);void printValue();private:T value_;
};// 在类外定义构造函数
template<typename T>
MyClass<T>::MyClass(T value) : value_(value) {// 构造函数的实现
}// 在类外定义成员函数
template<typename T>
void MyClass<T>::printValue() {std::cout << "Value: " << value_ << std::endl;
}int main() {MyClass<int> obj(42);obj.printValue();  // 输出:Value: 42return 0;
}

在这个例子中,MyClass 是一个类模板,它有一个类型参数 T。

构造函数 MyClass(T value) 和成员函数 void printValue() 都在类声明之外进行了定义。

注意,在类外定义模板类的成员函数时,必须使用 template<typename T> 开头,并且函数名前面要加上 MyClass<T>:: 来指明这个函数是哪个模板类的成员。

这种方式的好处是可以让类声明更加简洁,而将函数的复杂实现细节隐藏在类声明之外。同时,如果函数实现非常长或者需要包含其他头文件,这样做也可以减少类声明部分的依赖和复杂性。

类模板成员函数的实例化

默认情况下,一个类模板的成员函数只有当程序用到它时才进行实例化。

在C++中,类模板的成员(成员函数或静态数据成员)并不是在类模板实例化时就被全部实例化。相反,成员函数只在实际被调用时才被实例化,而静态数据成员则在其定义时被实例化。

这种行为有助于减少编译时间和生成的代码大小,因为只有当特定的成员函数真正需要时,编译器才会为其生成代码。

下面是一个例子,演示了类模板成员函数在实际使用时才被实例化的概念:

#include <iostream>// 类模板声明
template<typename T>
class MyClass {
public:MyClass(T val) : value(val) {}// 成员函数声明void displayValue();void unusedFunction();private:T value;
};// 成员函数定义
template<typename T>
void MyClass<T>::displayValue() {std::cout << "Value: " << value << std::endl;
}// 另一个成员函数定义,但这个函数在后面的代码中从未被调用
template<typename T>
void MyClass<T>::unusedFunction() {std::cout << "This function is not used." << std::endl;
}int main() {// 使用int类型实例化类模板MyClass<int> intObject(42);intObject.displayValue(); // 此处调用了displayValue,因此该函数会被实例化// 注意:unusedFunction没有被调用,因此在这次编译中它不会被实例化return 0;
}


在上面的代码中,MyClass是一个类模板,它有两个成员函数:displayValue和unusedFunction。在main函数中,我们创建了一个MyClass<int>的实例,并且只调用了displayValue函数。因此,只有displayValue函数在这次编译过程中被实例化。尽管unusedFunction也是MyClass的成员函数,但由于在main函数中从未被调用,所以它在这次编译中不会被实例化。

编译器优化通常会确保只有真正需要的代码才会被生成,这有助于减少最终可执行文件的大小并提高性能。如果你尝试在代码中查找unusedFunction函数的实例化,你会发现它并不存在,除非你在某处显式地调用了它。

如果一个成员函数没有被使用,则它不会被实例化。

成员函数只有在被用到时才进行实例化,这一特性使得即使某种类型不能完全符合模板操作的要求,我们仍然能用该类型实例化类。

默认情况下,对于一个实例化了的类模板,其成员只有在使用时才被实例化。

在类代码内简化模板类名的使用

当我们使用一个类模板类型时必须提供模板实参,但这一规则有一个例外。

在类模板自己的作用域中,我们可以直接使用模板名而不提供实参:

在类模板的定义内部,当引用模板自身或其成员时,我们不需要提供模板实参。编译器能够推断出当前的上下文,并知道我们是在引用模板自身的当前实例化。这意味着,在类模板成员函数或内部类型的定义中,我们可以直接使用模板名来引用当前模板实例的成员。

例如,考虑以下类模板定义:

 template <typename T>  class MyClass {  public:  MyClass() : value(T()) {}  void setValue(T newValue) {  value = newValue;  }  T getValue() const {  return value;  }  // 在成员函数内部,我们可以直接使用MyClass而不提供模板实参  MyClass* createCopy() const {  return new MyClass(*this); // 这里MyClass指的是MyClass<T>  }  private:  T value;  }; 

在成员函数createCopy中,我们使用了new MyClass(*this);来创建一个当前模板实例的拷贝。在这个上下文中,MyClass自动解析为MyClass<T>,其中T是模板实例化的类型。我们不需要写成new MyClass<T>(*this);,因为编译器已经知道我们在引用哪个实例化。

同样地,如果我们在类模板内部定义一个嵌套类型或函数,我们也可以直接使用模板名:

 template <typename T>  class Outer {  public:  class Inner { // 嵌套类定义  public:  Inner() : value(T()) {}  T value;  };  // 成员函数内部使用嵌套类  Inner createInner() {  return Inner(); // 这里Inner自动指的是Outer<T>::Inner  }  }; 


在这个例子中,Inner类是在Outer类模板内部定义的,当我们在Outer的方法中引用Inner时,也不需要提供模板实参。编译器理解我们在引用当前Outer<T>实例中的Inner类。

在类模板外使用类模板名

当我们在类模板外定义其成员时,必须记住,我们并不在类的作用域中,直到遇到类名才表示进入类的作用域:

//后置:递增/递减对象但返回原值
template <typename T>
BlobPtr<T> BlobPtr<T>::operator++(int)
{
//此处无须检查;调用前置递增时会进行检查
BlobPtr ret = *this; //保存当前值
++*this; //推进一个元素;前置++检查递增是否合法
return ret;// 返回保存的状态
}

由于返回类型位于类的作用域之外,我们必须指出返回类型是一个实例化的 BlobPtr,它所用类型与类实例化所用类型一致

在函数体内,我们已经进入类的作用域,因此在定义 ret时无须重复模板实参。如果不提供模板实参,则编译器将假定我们使用的类型与成员实例化所用类型一致。

因此,ret的定义与如下代码等价:

BlobPtr<T> ret =*this;

在一个类模板的作用城内,我们可以直接使用模板名而不必指定模板实参。

类模板和友元

当一个类包含一个友元声明时,类与友元各自是否是模板是相互无关的。

如果一个类模板包含一个非模板友元,则友元被授权可以访问所有模板实例。

如果友元自身是模板,类可以授权给所有友元模板实例,也可以只授权给特定实例。

一对一友好关系

类模板与另一个(类或函数)模板间友好关系的最常见的形式是建立对应实例及其友元间的友好关系。

以下是一个结合了类模板和函数模板的例子,

其中类模板MyClass表示一个简单的动态数组,而函数模板PrintArray则被设计为能够打印任意类型的数组。PrintArray函数模板被声明为MyClass的友元,因此它可以访问MyClass的私有成员。
 

 #include <iostream>  #include <vector>  // 类模板 MyClass,表示一个简单的动态数组  template<typename T>  class MyClass {  // 声明 PrintArray<T> 为 MyClass<T> 的友元  template<typename U> friend void PrintArray(const MyClass<U>& obj);  private:  std::vector<T> data;  public:  MyClass(std::initializer_list<T> list) : data(list) {}  void add(const T& value) {  data.push_back(value);  }  };  // 函数模板 PrintArray,用于打印 MyClass 类型的数组内容  template<typename T>  void PrintArray(const MyClass<T>& obj) {  std::cout << "[";  for (size_t i = 0; i < obj.data.size(); ++i) {  std::cout << obj.data[i];  if (i < obj.data.size() - 1) {  std::cout << ", ";  }  }  std::cout << "]" << std::endl;  }  int main() {  MyClass<int> intArray = {1, 2, 3, 4, 5};  MyClass<double> doubleArray = {1.1, 2.2, 3.3, 4.4, 5.5};  PrintArray(intArray); // 输出: [1, 2, 3, 4, 5]  PrintArray(doubleArray); // 输出: [1.1, 2.2, 3.3, 4.4, 5.5]  return 0;  } 

在这个例子中,MyClass是一个类模板,它使用std::vector来存储数据,并提供了一个添加元素的方法。PrintArray是一个函数模板,它被设计为可以打印任何类型的MyClass对象的内容。由于PrintArray被声明为MyClass的友元函数模板,因此它可以访问MyClass的私有成员data。

在main函数中,我们创建了两个MyClass对象,一个用于整数,另一个用于双精度浮点数,并使用PrintArray函数模板来打印它们的内容。由于PrintArray是模板函数,它可以与任何类型的MyClass一起使用,只要这些类型是兼容的。

通用和特定的模板友好关系

一个类也可以将另一个模板的每个实例都声明为自己的友元,或者限定特定的实例为友元:

//前置声明,在将模板的一个特定实例声明为友元时要用到
template <typename T> class Pal;
class C
{
//C是一个普通的非模板类
friend class Pal<C>; //用类C实例化的Pal是C的一个友元// Pal2的所有实例都是C的友元;这种情况无须前置声明
template <typename T> friend class Pal2;
};template <typename T> class C2 
{ // C2本身是一个类模板// C2的每个实例将相同实例化的Pal声明为友元friend class Pal<T>;// Pal的模板声明必须在作用域之内// Pal2的所有实例都是C2的每个实例的友元,不需要前置声明
template <typename X> friend class Pal2;// Pal3是一个非模板类,它是C2所有实例的友元
friend class Pal3;// 不需要Pa13的前置声明
};


为了让所有实例成为友元,友元声明中必须使用与类模板本身不同的模板参数。


令模板自己的类型参数成为友元

在新标准中,我们可以将模板类型参数声明为友元;

template <typename Type> 
class Bar 
{
friend Type;// 将访问权限授予用来实例化Bar的类型
//...
};

此处我们将用来实例化Bar的类型声明为友元。

因此,对于某个类型名Foo,Foo将成为为Bar<Foo>的友元,Sales_data将成为Bar<Sales_data>的友元,依此类推,

值得注意的是,虽然友元通常来说应该是一个类或是一个函数,但我们完全可以用一个内置类型来实例化Bar。

这种与内置类型的友好关系是允许的,以便我们能用内置类型来实例化Bar这样的类。

模板类型别名

类模板的一个实例定义了一个类类型,与任何其他类类型一样,我们可以定义一个typedef来引用实例化的类:

typedef Blob<string> StrBlob;

由于模板不是一个类型,我们不能定义一个typedef引用一个模板。即,无法定义一个typedef引用Blob<T>

但是,新标准允许我们为类模板定义一个类型别名:

template<typename T> using twin = pair<T, T>;
twin<string> authors; // authors是一个pair<string, string>

在这段代码中,我们将twin定义为成员类型相同的pair的别名。这样,twin的用户只需指定一次类型。

一个模板类型别名是一族类的别名:

twin<int> win_loss; // win_loss 是一个pair<int, int>
twin<double> area; // area是一个pair<double, double>

就像使用类模板一样,当我们使用twin时,需要指出希望使用哪种特定类型的twin。

当我们定义一个模板类型别名时,可以固定一个或多个模板参数;

template <typename T> using partNo = pair<T, unsigned>;
partNo<string> books;// books是一个pair<string, unsigned>
partNo<Vehicle> cars;// cars是一个pair<Vehicle, unsigned>
partNo<Student> kids; // kids是一个pair<student, unsigned>

这段代码中我们将 partNo 定义为一族类型的别名,这族类型是 second 成员为unsigned的pair. partNo的用户需要指出pair的first成员的类型,但不能指定second成员的类型。

类模板的static成员

与任何其他类相同,类模板可以声明static成员;

template <typename T> 
class Foo 
{
public:static std::size_t count() ( return ctr; )
//其他接口成员
private:
static std::size_t ctr;
// 其他实现成员
};

在这段代码中,Foo是一个类模板,它有一个名为count的public static成员函数一个名为ctr的private static数据成员。

每个Foo的实例都有其自己的static成员实例。即,对任意给定类型X,都有一个 Foo<x>::ctr 和一个 Foo<x>::count成员。所有Foo<X>类型的对象共享相同的ctr对象和count函数。

例如,

//实例化static 成员 Foo<string>::ctr和Foo<string>::count
Foo<string> fs;
//所有三个对象共享相同的Foo<int>::ctr和Foo<int>::count成员
Foo<int> fi, fi2, fi3;

与任何其他static数据成员相同,模板类的每个static数据成员必须有且仅有一个定义。

但是,类模板的每个实例都有一个独有的static对象。

因此,与定义模板的成员函数类似,我们将static数据成员也定义为模板:

template <typename T>
size_t Foo<T>::ctr =0;//定义并初始化ctr

与类模板的其他任何成员类似,定义的开始部分是模板参数列表,随后是我们定义的成员的类型和名字。与往常一样,成员名包括成员的类名,对于从模板生成的类来说,类名包括模板实参。因此,当使用一个特定的模板实参类型实例化Foo时,将会为该类类型实例化一个独立的ctr,并将其初始化为0。

与非模板类的静态成员相同,我们可以通过类类型对象来访问一个类模板的static成员,也可以使用作用域运算符直接访问成员。

当然,为了通过类来直接访问static成员,我们必须引用一个特定的实例:

Foo<int> fi; // 实例化Foo<int>类和static数据成员ctr
auto ct= Foo<int>::count(); //实例化Foo<int>::count
//使用 Foo<int>::count
ct = fi.count();
ct = Foo::count (); // 错误:使用哪个模板实例的count?

类似任何其他成员函数,一个static成员函数只有在使用时才会实例化。
 

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

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

相关文章

Windows常用快捷键(效率、组合键、文字编辑、文件、Home、End、Delete)

这是一行测试语言&#xff0c;没有其他的含义.这是一行测试语言, 没有其他的含义.这是一行测试语言, 没有其他的含义。这是一行测试语言, 没有其他的含义.这是一行测试语言, 没有其他的含义.这是一行测试语言&#xff0c;没有其他的含义。这是一行测试语言, 没有其他的含义.这是…

变量的作用范围:在函数中对全局变量进行赋值,python和JavaScript有点不一样。

JavaScript 和 Python 对于在函数中对全局变量进行赋值的行为略有不同&#xff1a; JavaScript&#xff1a; 在 JavaScript 中&#xff0c;函数可以对全局变量进行赋值&#xff0c;但需要注意以下几点&#xff1a; 如果在函数中直接使用变量名进行赋值&#xff0c;且该变量未…

上位机图像处理和嵌入式模块部署(qmacvisual之tcp客户端)

【 声明&#xff1a;版权所有&#xff0c;欢迎转载&#xff0c;请勿用于商业用途。 联系信箱&#xff1a;feixiaoxing 163.com】 视觉算法出了结果之后&#xff0c;一般都要通知到其他设备进行某些动作的。以前通信的方式&#xff0c;一般都是有线的&#xff0c;什么232、485、…

TiDB单机版安装和连接访问

TiDB单机版安装和连接访问 1、下载 $wget http://download.pingcap.org/tidb-latest-linux-amd64.tar.gz 2、解压缩 $tar -zxvf tidb-latest-linux-amd64.tar.gz 3、启动TiDB 启动PD $./bin/pd-server --data-dirpd --log-filepd.log 启动tikv $./bin/tikv-server --pd…

ARM IHI0069F GIC architecture specification (5)

Ch2 中断分配与路由 2.1 The Distributor and Redistributors Distributor 为 SPI 提供路由配置&#xff0c;并保存所有关联的路由和优先级信息。 Redistributor 提供 PPI 和 SGI 的配置设置。 Redistributor总是在有限的时间内向 CPU 接口呈现具有最高优先级的待处理中断。 …

957: 逆置单链表

学习版 【C语言】 #include<iostream> using namespace std; typedef struct LNode {char data;struct LNode* next;LNode(char x) :data(x), next(nullptr) {} }LNode; void creatlist(LNode *&L) {int n;char e;cin >> n;LNode* p1, * p2;p1 L;for (int i…

帝国CMS模板源码整站安装说明(图文)

安装步骤 第一步&#xff1a;先把得到的文件解压缩&#xff0c;把文件通过FTP传到空间里。&#xff08;请不要把类似www.lengleng.net这个文件夹传到FTP&#xff0c;请传这个大文件夹下面的所有文件夹和文件到空间根目录&#xff0c;请不要上传到2级目录&#xff0c;除非你自己…

Windows下用CMake编译PugiXML及配置测试

作者&#xff1a;翟天保Steven 版权声明&#xff1a;著作权归作者所有&#xff0c;商业转载请联系作者获得授权&#xff0c;非商业转载请注明出处 PugiXML是什么&#xff1f; PugiXML 是一个用于解析和操作 XML 文档的 C 库。它提供了简单易用的接口&#xff0c;能够高效地加载…

网络基础二——TCP可靠性实现机制补充

11.3.4确认应答机制 ​ 1.双方通信时要返回确认应答报文&#xff0c;保证对方发送的报文是有效的&#xff1b;尽管整个通信过程中无法保证数据全部可靠&#xff0c;但是可以保证单个方向发送的数据是可靠的&#xff1b; ​ 发送的报文要设置序号&#xff0c;如果是应答报文要…

为移动云数据实现基于可撤销属性组的加密:多代理辅助方法

参考文献为2023年发表的Achieving Revocable Attribute Group-Based Encryption for Mobile Cloud Data: A Multi-Proxy Assisted Approach 动机 对于目前的代理辅助的可撤销基于属性加密来说&#xff0c;外包解密存一些缺点。当多个具有相同属性的用户请求外包转换时&#x…

日期专题:做题笔记 (时间显示/星期计算/星系炸弹/第几天/纪念日)

目录 时间显示 代码 星期计算 代码 星系炸弹 代码 第几天 纪念日 代码 时间显示 时间显示 这道题主要是单位换算。 ①单位换算 ②输出格式&#xff1a; a. 不足两位补前导零。利用printf输出 b. 注意 long long 输出格式应该是 %lld 长整型 代码 #include <…

路由守卫拦截符合条件的路由,不放行

最近做毕设遇到一个问题&#xff0c;我有两个界面&#xff0c;一个是注册&#xff0c;一个是注册成功&#xff0c;对应的路由为/register和/registerSuccess&#xff0c;怎么实现只能通过注册界面的按钮才能跳转到注册成功界面&#xff0c;直接输入/registerSuccess路由会拦截,…

Python 之 Fastapi 框架学习

依赖安装 Fastapi 有版本要求&#xff0c;需要的 Python 版本至少是 Python 3.8&#xff08;不要犟&#xff0c;按照版本要求来&#xff0c;我最先也是在我 Python3.6 上装的&#xff0c;果不其然跑不起来&#xff09;&#xff0c;幸好我 Win7 老古董能支持的 Python 最高版本…

《C++程序设计》阅读笔记【1-函数】

&#x1f308;个人主页&#xff1a;godspeed_lucip &#x1f525; 系列专栏&#xff1a;《C程序设计》阅读笔记 本文对应的PDF源文件请关注微信公众号程序员刘同学&#xff0c;回复C程序设计获取下载链接。 1 函数1.1 概述1.2 函数定义、声明、原型1.3 变量1.3.1 全局变量1.3.…

内部类(来自类和对象的补充)

❤️❤️前言~&#x1f973;&#x1f389;&#x1f389;&#x1f389; hellohello~&#xff0c;大家好&#x1f495;&#x1f495;&#xff0c;这里是E绵绵呀✋✋ &#xff0c;如果觉得这篇文章还不错的话还请点赞❤️❤️收藏&#x1f49e; &#x1f49e; 关注&#x1f4a5;&a…

13.JavaWeb XML:构建结构化数据的重要工具

目录 导语&#xff1a; 一、XML概念 &#xff08;1&#xff09;可拓展 &#xff08;2&#xff09;功能-存储数据 &#xff08;3&#xff09;xml与html的区别 二、XML内容 三、XML用途 四、案例&#xff1a;使用XML构建在线书店的书籍数据库 结语&#xff1a; 导语&…

HTMLCSSJS

HTML基本结构 <html><head><title>标题</title></head><body>页面内容</body> </html> html是一棵DOM树, html是根标签, head和body是兄弟标签, body包括内容相关, head包含对内容的编写相关, title 与标题有关.类似html这种…

非写代码无以致远

标题党一下&#xff0c;本篇文章主要汇总了一些代码题&#xff0c;让大家写一些代码练习一下吧&#xff01; 变种水仙花_牛客题霸_牛客网 (nowcoder.com) #include<stdio.h> int main() {for (int i 10000; i < 99999; i) {int sum 0;for (int j 10; j < 1000…

Linux操作系统之防火墙

目录 一、防火墙 1、防火墙的类别 2、安装iptables(四表五链&#xff09; ​​​​​​​一、防火墙 1、防火墙的类别 安全产品 杀毒 针对病毒&#xff0c;特征篡改系统中文件杀毒软件针对处理病毒程序 防火墙 针对木马&#xff0c;特征系统窃密 防火墙针对处理木马 防火墙…

Python 一步一步教你用pyglet制作“彩色方块连连看”游戏(续)

“彩色方块连连看”游戏(续) 上期讲到相同的色块连接&#xff0c;链接见&#xff1a; Python 一步一步教你用pyglet制作“彩色方块连连看”游戏-CSDN博客 第八步 续上期&#xff0c;接下来要实现相邻方块的连线&#xff1a; 首先来进一步扩展 行列的类&#xff1a; class R…