利用虚函数指针实现多态编程_第1页
利用虚函数指针实现多态编程_第2页
利用虚函数指针实现多态编程_第3页
利用虚函数指针实现多态编程_第4页
利用虚函数指针实现多态编程_第5页
已阅读5页,还剩21页未读 继续免费阅读

下载本文档

版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领

文档简介

24/26利用虚函数指针实现多态编程第一部分虚函数指针:多态的基础 2第二部分对象的实际类型与指针的指向类型 4第三部分虚函数调用:动态绑定与静态绑定 7第四部分虚函数表的内部结构与工作原理 11第五部分虚函数的动态类型检查与类型转换 14第六部分纯虚函数与抽象类:接口与实现分离 18第七部分多级继承中的虚函数调用顺序与覆盖 22第八部分虚函数指针与多态编程的优缺点 24

第一部分虚函数指针:多态的基础关键词关键要点【虚函数指针:多态的基础】:

1.多态:多态性是面向对象编程的重要特征,允许对象具有不同的形式和行为,同时保持其基本特性。

2.虚函数:虚函数是一种特殊类型的成员函数,它允许对象的子类以不同的方式实现该函数。

3.虚函数指针:虚函数指针指向虚函数的内存地址,它存储在对象的虚函数表中。

【虚函数表:实现多态的关键】:

#虚函数指针:多态的基础

虚函数指针概述

虚函数指针是C++中实现多态的核心机制。它是一种指向虚函数表地址的指针,使一个父类对象能够调用派生类的虚函数。当派生类对象被赋给父类指针时,虚函数指针就发挥了作用,它允许父类指针调用派生类的虚函数。

虚函数表

虚函数表是包含虚函数地址的表。当一个类定义了一个或多个虚函数时,编译器就会为该类创建一个虚函数表。虚函数表中的每个条目都包含指向虚函数的指针。虚函数表的存在使得父类指针可以调用派生类的虚函数。

实例

考虑以下代码示例:

```c++

public:

cout<<"Animalspeaks"<<endl;

}

};

public:

cout<<"Dogbarks"<<endl;

}

};

Animal*animal=newDog();

animal->speak();//Outputs"Dogbarks"

return0;

}

```

在这个示例中,`Animal`类定义了一个虚函数`speak()`。`Dog`类继承自`Animal`类并覆盖了`speak()`函数。当我们创建一个`Dog`对象并将其赋给一个`Animal`指针时,虚函数指针就发挥了作用。当我们调用`animal->speak()`时,虚函数指针会指向`Dog`类的`speak()`函数,从而输出"Dogbarks"。

虚函数指针的好处

虚函数指针具有以下好处:

*实现多态:虚函数指针是实现多态的关键机制,它使父类指针可以调用派生类的虚函数,从而实现多态。

*解耦基类和派生类:虚函数指针使基类和派生类之间解耦。这意味着基类代码无需知道派生类的具体实现细节,只需要知道虚函数的接口即可。

*提高代码的可扩展性:虚函数指针提高了代码的可扩展性。当添加新的派生类时,无需修改基类代码,只需要在派生类中覆盖虚函数即可。

虚函数指针的局限性

虚函数指针也存在一些局限性:

*性能开销:虚函数指针会带来一定的性能开销。这是因为在调用虚函数时,需要通过虚函数指针间接调用,这比直接调用函数要慢一些。

*难以理解:虚函数指针对于初学者来说可能难以理解。这是因为虚函数指针涉及到一些底层实现细节,需要深入理解C++的运行时机制。

结论

虚函数指针是C++中实现多态的核心机制。它使父类指针可以调用派生类的虚函数,从而实现多态。虚函数指针具有许多好处,但也存在一些局限性。在使用虚函数指针时,需要权衡其利弊,以达到最佳的性能和可维护性。第二部分对象的实际类型与指针的指向类型关键词关键要点【对象类型的确定】:

1.虚函数指针存储在对象的内存布局中,它指向对象的虚函数表。

2.虚函数表包含指向该类所有虚函数的指针。

3.当对象被创建时,它的类型被确定,并且对象的虚函数指针被设置指向该类型的虚函数表。

【指针类型的影响】:

对象的实际类型与指针的指向类型

在虚函数指针实现多态编程中,对象的实际类型与指针的指向类型之间存在着以下几种情况:

1.指针的指向类型与对象的实际类型相同

在这种情况下,指针指向的对象就是该指针所指向类型的对象。例如:

```

public:

};

public:

};

A*pa=newA();

B*pb=newB();

pa->f();//输出"A::f()"

pb->f();//输出"B::f()"

```

在这个例子中,`pa`指向的对象是一个`A`类型的对象,`pb`指向的对象是一个`B`类型的对象。当通过指针调用`f()`函数时,会根据指针指向的对象的实际类型来调用相应的函数。

2.指针的指向类型与对象的实际类型不同

在这种情况下,指针指向的对象并不是该指针所指向类型的对象。例如:

```

public:

};

public:

};

A*pa=newB();

pa->f();//输出"B::f()"

```

在这个例子中,`pa`指向的对象是一个`B`类型的对象,但`pa`的指向类型是`A*`。当通过`pa`调用`f()`函数时,会根据`pa`所指向的对象的实际类型来调用相应的函数,因此输出"B::f()”。

3.指针的指向类型为虚基类类型

在这种情况下,指针指向的对象可以是虚基类或派生类的对象。例如:

```

public:

};

public:

};

public:

};

public:

};

A*pa=newD();

pa->f();//输出"D::f()"

```

在这个例子中,`pa`指向的对象是一个`D`类型的对象,但`pa`的指向类型是`A*`。当通过`pa`调用`f()`函数时,会根据`pa`所指向的对象的实际类型来调用相应的函数,因此输出"D::f()”。

4.指针的指向类型为抽象基类类型

在这种情况下,指针不能指向任何对象,只能指向抽象基类的指针。例如:

```

public:

virtualvoidf()=0;

};

A*pa;//错误:不能定义抽象基类的指针

```

在这个例子中,`A`是一个抽象基类,因此不能定义指向`A`类型的指针。第三部分虚函数调用:动态绑定与静态绑定关键词关键要点虚函数调用

1.虚函数调用是多态性的关键所在,它允许在不同类型对象上调用相同的虚函数,并且可以根据对象的实际类型执行不同的实现。

2.虚函数调用分为动态绑定和静态绑定两种方式。动态绑定是指在运行时才确定要调用的虚函数实现,而静态绑定是指在编译时就确定要调用的虚函数实现。

3.动态绑定和静态绑定各有优缺点。动态绑定的优点是灵活性高,可以实现真正的多态性,但缺点是性能较差。静态绑定的优点是性能高,但缺点是灵活性差,不能实现真正的多态性。

动态绑定

1.动态绑定是指在运行时才确定要调用的虚函数实现。这是通过在基类中维护一个虚函数表来实现的,虚函数表中存储着指向虚函数实现的指针。

2.当调用一个虚函数时,编译器会根据对象的实际类型查找虚函数表中的相应函数实现,然后执行该函数实现。

3.动态绑定可以实现真正的多态性,因为它允许在不同类型对象上调用相同的虚函数,并且可以根据对象的实际类型执行不同的实现。

静态绑定

1.静态绑定是指在编译时就确定要调用的虚函数实现。这是通过在基类中维护一个虚函数表来实现的,虚函数表中存储着指向虚函数实现的指针。

2.当调用一个虚函数时,编译器会根据对象的实际类型查找虚函数表中的相应函数实现,然后执行该函数实现。

3.静态绑定可以提高性能,因为它不需要在运行时进行查找虚函数表的开销。但是,静态绑定不能实现真正的多态性,因为它无法在不同类型对象上调用相同的虚函数。#利用虚函数指针实现多态编程

虚函数调用:动态绑定与静态绑定

一、虚函数调用过程

1.函数查找

当调用一个虚函数时,编译器会检查类是否定义了该虚函数,如果没有,则继续在基类中查找,直到找到该虚函数的定义。

2.虚函数表(vtable)

虚函数表是一个数据结构,它存储了所有虚函数的地址。当一个类定义了一个虚函数时,编译器会为该类生成一个虚函数表,并把虚函数表的地址存储在类的对象中。

3.虚函数指针

每个类都有一个虚函数指针,指向该类的虚函数表。当调用一个虚函数时,编译器会使用这个虚函数指针来找到该虚函数的地址,然后调用该虚函数。

二、动态绑定与静态绑定

1.动态绑定

动态绑定是指在运行时才确定调用哪个函数。这是通过虚函数指针实现的。当一个虚函数被调用时,编译器会使用虚函数指针来找到该虚函数的地址,然后调用该虚函数。

2.静态绑定

静态绑定是指在编译时就已经确定调用哪个函数。这是通过重载函数实现的。当一个函数被重载时,编译器会根据实参的类型来决定调用哪个函数。

三、动态绑定与静态绑定的比较

|特征|动态绑定|静态绑定|

||||

|绑定时间|运行时|编译时|

|灵活度|更灵活|不灵活|

|效率|效率较低|效率较高|

|使用场景|适用于需要在运行时改变函数行为的情况|适用于函数的行为在编译时就已经确定不会改变的情况|

四、虚函数指针的应用

虚函数指针可以用于实现多态编程,即同一个函数可以对不同的对象执行不同的操作。例如,以下代码定义了一个虚函数`draw()`,该函数可以对不同的图形对象执行不同的绘制操作。

```c++

public:

virtualvoiddraw()=0;

};

public:

//绘制圆形

}

};

public:

//绘制矩形

}

};

Shape*shape=newCircle();

shape->draw();//绘制圆形

shape=newRectangle();

shape->draw();//绘制矩形

}

```

在这个例子中,`Shape`类是一个抽象类,它定义了一个纯虚函数`draw()`.`Circle`类和`Rectangle`类都是`Shape`类的子类,它们都重写了`draw()`函数,以实现不同的绘制操作。当调用`draw()`函数时,编译器会根据对象的类型来决定调用哪个函数。第四部分虚函数表的内部结构与工作原理关键词关键要点【虚函数表的内部结构】:

1.虚函数表通常以数组的形式存储在内存中,每个虚函数都有自己的一个槽位。

2.虚函数表中的每个槽位都包含一个函数指针,指向该虚函数在内存中的实际地址。

3.虚函数表通常存储在对象的开头,这样可以方便地访问该对象的虚函数。

【虚函数表的查找机制】:

虚函数表的内部结构

虚函数表是一个特殊的数据结构,它包含了所有虚函数的地址。虚函数表在程序运行时由编译器自动生成,并存储在程序的内存中。虚函数表的内部结构通常如下:

*虚函数表指针:每个类都有一个虚函数表指针,指向该类的虚函数表。虚函数表指针通常存储在对象的第一个字节中。

*虚函数地址:虚函数表中包含所有虚函数的地址。虚函数的地址通常存储在虚函数表中的连续内存位置中。

*虚函数类型信息:虚函数表中还包含虚函数的类型信息。虚函数的类型信息通常存储在虚函数表中的第一个字节中。

虚函数表的原理

虚函数表的原理如下:

*当一个对象调用一个虚函数时,编译器会首先根据对象的虚函数表指针找到该虚函数的地址。

*然后,编译器会根据虚函数的地址找到该虚函数的实现代码。

*最后,编译器会调用该虚函数的实现代码。

虚函数表的原理保证了多态性的实现。多态性是指,同一个函数可以对不同的类对象执行不同的操作。虚函数表的原理保证了,当一个对象调用一个虚函数时,编译器会根据对象的虚函数表指针找到该虚函数的地址,然后会根据虚函数的地址找到该虚函数的实现代码,最后会调用该虚函数的实现代码。这样,同一个函数就可以对不同的类对象执行不同的操作。

虚函数表的实现

虚函数表的实现通常有两种方式:

*基于指针的虚函数表:基于指针的虚函数表是使用指针来存储虚函数的地址。基于指针的虚函数表实现简单,但是开销较大。

*基于对象的虚函数表:基于对象的虚函数表是使用对象来存储虚函数的地址。基于对象的虚函数表实现开销较小,但是实现复杂。

不同的编译器和编程语言可能采用不同的方式来实现虚函数表。但是,虚函数表的原理是相同的,即通过虚拟函数指针指向虚函数表,从而实现多态性。

虚函数表的优点

虚函数表具有以下优点:

*实现多态性:虚函数表保证了多态性的实现。同一个函数可以对不同的类对象执行不同的操作。

*提高代码的可维护性:虚函数表提高了代码的可维护性。当需要修改虚函数的实现时,只需要修改虚函数表的实现代码,而不需要修改所有调用该虚函数的代码。

*提高代码的可扩展性:虚函数表提高了代码的可扩展性。当需要添加新的虚函数时,只需要将新的虚函数添加到虚函数表中,而不需要修改所有调用该虚函数的代码。

虚函数表的缺点

虚函数表也有一些缺点:

*开销较大:虚函数表开销较大。因为虚函数表需要存储所有虚函数的地址,所以虚函数表会占用一定的内存空间。

*降低代码的性能:虚函数表降低了代码的性能。因为虚函数表需要在运行时查找虚函数的地址,所以虚函数表的调用比直接调用的开销更大。

总体来说,虚函数表是一种实现多态性的有效方法。虚函数表具有实现多态性、提高代码的可维护性、提高代码的可扩展性等优点,但是也有开销较大、降低代码性能等缺点。在实际开发中,需要根据实际情况选择是否使用虚函数表。第五部分虚函数的动态类型检查与类型转换关键词关键要点虚函数的动态类型检查

1.虚函数的动态类型检查机制,memungkinkanparapemrogramuntukmenuliskodeyangdapatbekerjadenganberbagaijenisobjektanpamengetahuikelasspesifiknyasebelumnya.

2.当一个虚函数被调用时,编译器会根据对象的实际类型来确定要调用哪个函数版本。

3.虚函数的动态类型检查提供了灵活性,使其能够轻松地创建可重用和可扩展的代码。

虚函数的类型转换

1.虚函数的类型转换允许将一个类型的对象强制转换为另一个类型的对象。

2.类型转换可以通过强制转换运算符(static_cast)或动态转换运算符(dynamic_cast)来实现。

3.强制转换运算符只检查类型的兼容性,而动态转换运算符还执行运行时类型检查。虚函数的动态类型检查与类型转换

虚函数的动态类型检查和类型转换是多态编程的重要技术,它允许在运行时确定对象的实际类型并执行相应的操作。

#动态类型检查

动态类型检查是在运行时确定对象的实际类型的过程。在C++中,可以使用`typeid`运算符来进行动态类型检查。`typeid`运算符返回一个`type_info`对象,该对象包含有关对象的类型的信息。例如,以下代码使用`typeid`运算符来检查`p`所指向对象的实际类型:

```c++

Base*p=newDerived();

std::cout<<typeid(*p).name()<<std::endl;//输出:Derived

```

#类型转换

类型转换是将一种类型的值转换为另一种类型的值的过程。在C++中,可以使用`static_cast`运算符和`dynamic_cast`运算符来进行类型转换。`static_cast`运算符用于进行静态类型转换,即在编译时确定转换类型;`dynamic_cast`运算符用于进行动态类型转换,即在运行时确定转换类型。例如,以下代码使用`static_cast`运算符将`p`所指向对象的类型转换为`Derived`类型:

```c++

Base*p=newDerived();

Derived*d=static_cast<Derived*>(p);

```

以下代码使用`dynamic_cast`运算符将`p`所指向对象的类型转换为`Derived`类型:

```c++

Base*p=newDerived();

Derived*d=dynamic_cast<Derived*>(p);

//p指向Derived对象

//p不指向Derived对象

}

```

#虚函数的动态类型检查与类型转换示例

以下是一个虚函数的动态类型检查与类型转换的示例:

```c++

#include<iostream>

usingnamespacestd;

public:

cout<<"Base::print()"<<endl;

}

};

public:

cout<<"Derived::print()"<<endl;

}

};

Base*p=newDerived();

//动态类型检查

cout<<"p指向Derived对象"<<endl;

cout<<"p不指向Derived对象"<<endl;

}

//类型转换

Derived*d=dynamic_cast<Derived*>(p);

d->print();//输出:Derived::print()

cout<<"无法将p转换为Derived类型"<<endl;

}

return0;

}

```

输出:

```

p指向Derived对象

Derived::print()

```

在这个示例中,我们首先创建一个`Derived`对象的指针`p`,然后使用`typeid`运算符检查`p`所指向对象的实际类型。结果表明`p`指向一个`Derived`对象。接下来,我们使用`dynamic_cast`运算符将`p`所指向的对象转换为`Derived`类型,并调用`print()`方法。结果表明`p`指向一个`Derived`对象,并且`print()`方法被正确调用。

#虚函数的动态类型检查与类型转换的应用

虚函数的动态类型检查与类型转换在多态编程中有着广泛的应用,例如:

*实现多态接口:虚函数的动态类型检查与类型转换允许在运行时确定对象的实际类型并执行相应的操作,从而实现多态接口。例如,在图形库中,`Shape`类可以定义一个`draw()`方法,而`Circle`、`Square`和`Triangle`等子类可以重写`draw()`方法,以便在调用`draw()`方法时根据对象的实际类型执行不同的操作。

*实现工厂模式:虚函数的动态类型检查与类型转换允许在运行时创建不同类型的对象,从而实现工厂模式。例如,在汽车工厂中,`CarFactory`类可以定义一个`createCar()`方法,而`Sedan`、`SUV`和`Truck`等子类可以重写`createCar()`方法,以便在调用`createCar()`方法时根据不同的参数创建不同类型的汽车对象。

*实现模板方法模式:虚函数的动态类型检查与类型转换允许在运行时确定对象的实际类型并执行相应的操作,从而实现模板方法模式。例如,在排序算法中,`SortAlgorithm`类可以定义一个`sort()`方法,而`BubbleSort`、`SelectionSort`和`QuickSort`等子类可以重写`sort()`方法,以便在调用`sort()`方法时根据不同的参数使用不同的排序算法对数据进行排序。

总的来说,虚函数的动态类型检查与类型转换是多态编程的重要技术,它允许在运行时确定对象的实际类型并执行相应的操作,从而实现多态接口、工厂模式和模板方法模式等设计模式。第六部分纯虚函数与抽象类:接口与实现分离关键词关键要点纯虚函数与抽象类

1.什么是纯虚函数?纯虚函数是指没有函数体(函数定义中不包括函数代码块)的虚函数。只有声明,没有实现。

2.抽象类是什么?抽象类是指至少包含一个纯虚函数的类。不能创建抽象类的实例,但是可以通过使用抽象类并从该类继承来创建派生类。

3.接口与实现分离:接口与实现分离是一种设计方法,它强调了应该将接口(抽象类与纯虚函数)和实现(派生类与函数实现体)分离。

纯虚函数的优点

1.提高代码的可扩展性:纯虚函数允许在不改变基类代码的情况下扩展基类。派生类可以提供自己的实现来满足自己的特定需求。

2.实现多态性:纯虚函数是实现多态性的基础。通过使用纯虚函数,基类可以定义一个接口,而派生类可以提供实现该接口的不同方式。

3.提高代码的抽象性:纯虚函数有助于提高代码的抽象性,因为基类无需知道派生类的实现细节。

纯虚函数的缺点

1.增加了代码的复杂性:纯虚函数可能会增加代码的复杂性,因为需要定义接口和实现。

2.增加了运行时的开销:纯虚函数可能会增加运行时的开销,因为需要在运行时进行动态绑定。

3.可能导致错误:纯虚函数如果使用不当可能导致错误,例如派生类没有提供纯虚函数的实现。纯虚函数与抽象类:接口与实现分离

1.纯虚函数

纯虚函数是一种没有函数体、而只包含一个纯虚函数声明的成员函数。代码中需要在纯虚函数声明中使用`=0`声明。纯虚函数通常用作基类的成员函数,因为它们不能在基类中实现,而必须在派生类中实现。派生类可以覆盖基类的纯虚函数,并提供自己的实现。

```c++

public:

virtualvoiddraw()=0;//纯虚函数

};

```

上面代码中,`Shape`类有一个纯虚函数`draw()`。该函数没有函数体,只能在派生类中实现。

2.抽象类

抽象类是指包含一个或多个纯虚函数的类。抽象类不能被实例化,只能作为基类使用。派生类可以从抽象类继承,并覆盖抽象类的纯虚函数。

```c++

public:

virtualvoiddraw()=0;//纯虚函数

};

public:

//实现绘制圆形的代码

}

};

public:

//实现绘制正方形的代码

}

};

```

上面代码中,`Shape`类是一个抽象类,因为它包含一个纯虚函数`draw()`。`Circle`和`Square`类从`Shape`类继承,并覆盖了`draw()`函数。这样,`Circle`和`Square`类就可以实例化,并调用`draw()`函数来绘制圆形和正方形。

3.接口与实现分离

纯虚函数和抽象类可以用于实现接口与实现分离。接口是指一组函数的声明,而实现是指这些函数的具体实现。纯虚函数声明了接口,而派生类提供了实现。

这样,就可以将接口和实现分开,从而提高代码的可维护性和扩展性。例如,如果要添加一个新形状,只需要创建一个新的派生类,并覆盖`draw()`函数。而不需要修改基类或其他派生类。

4.多态性

纯虚函数和抽象类是实现多态性的关键。多态性是指对象可以根据其类型调用不同的函数。例如,`Shape`类的派生类`Circle`和`Square`都可以调用`draw()`函数,但是它们会调用不同的实现。

```c++

Shape*shape=newCircle();

shape->draw();//调用Circle::draw()

shape=newSquare();

shape->draw();//调用Square::draw()

```

上面代码中,`shape`指针可以指向不同的派生类对象。当调用`shape->draw()`时,会调用相应派生类的`draw()`函数。这种特性称为多态性。

5.总结

纯虚函数和抽象类是C++语言中非常重要的概念。它们可以用于实现接口与实现分离和多态性。这些特性可以提高代码的可维护性和扩展性。第七部分多级继承中的虚函数调用顺序与覆盖关键词关键要点【多级继承中的虚函数调用顺序与覆盖】:

1.多级继承中,子类继承父类的虚函数时,子类可以覆盖父类的虚函数,也可以不覆盖父类的虚函数。

2.当子类覆盖父类的虚函数时,子类的虚函数将替换父类的虚函数,在子类对象中调用该虚函数时,将调用子类的虚函数,而不会调用父类的虚函数。

3.当子类不覆盖父类的虚函数时,子类对象中调用该虚函数时,将调用父类的虚函数。

【虚函数的动态绑定】:

多级继承中的虚函数调用顺序与覆盖

#虚函数调用顺序

在多级继承中,虚函数的调用顺序由虚函数表的结构和继承关系决定。虚函数表是一个由类名和虚函数地址组成的数组,每个类都有自己的虚函数表。虚函数表中的虚函数地址按照虚函数在类中的声明顺序排列。当调用一个虚函数时,编译器会先找到该虚函数在虚函数表中的位置,然后通过虚函数地址调用该虚函数。

在多级继承中,虚函数的调用顺序遵循以下规则:

1.最先调用的虚函数是基类的虚函数。

2.然后依次调用派生类的虚函数,直到调用到最派生类的虚函数。

#虚函数覆盖

在多级继承中,派生类可以覆盖基类的虚函数。覆盖是指派生类重新定义基类的虚函数。当派生类覆盖基类的虚函数时,派生类对象的虚函数表中该虚函数的地址将覆盖基类对象的虚函数表中该虚函数的地址。这意味着,当调用派生类对象的虚函数时,将调用派生类覆盖的虚函数,而不是基类的虚函数。

虚函数覆盖可以实现多态编程。多态编程是指派生类对象可以被当成基类对象使用,而不需要显式地指定派生类对象的类型。当调用派生类对象的虚函数时,将调用派生类覆盖的虚函数,而不是基类的虚函数。这使得程序员可以编写出更加灵活和可扩展的代码。

#实例

```c++

public:

};

p

温馨提示

  • 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
  • 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
  • 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
  • 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
  • 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
  • 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
  • 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。

评论

0/150

提交评论