C++ primer 第14章 操作重载与类型转换

文章目录

  • 基本概念
    • 直接调用一个重载的运算符函数
    • 某些运算符不应该被重载
    • 使用与内置类型一致的含义
    • 选择作为成员或者非成员
  • 输入和输出运算符
    • 重载输出运算符<<
      • 输出运算符尽量减少格式化操作
      • 输入输出运算符必须是非成员函数
    • 重载输入运算符>>
  • 算术和关系运算符
    • 相等运算符
    • 关系运算符
  • 赋值运算符
    • 复合赋值运算符
  • 下标运算符
  • 递增和递减运算符
    • 区分前置和后置运算符
    • 显式地调用后置运算符
  • 成员访问运算符
  • 函数调用运算符
    • 含有状态的函数对象类
    • lambda是函数对象
      • 表示lambda及相应捕获行为的类
    • 标准库定义的函数对象
      • 在算法中使用标准库函数对象
      • transform函数
    • 可调用对象与function
      • 不同类型可能具有相同的调用形式
      • 重载的函数与function
  • 重载、类型转换与运算符
    • 类型转换运算符
      • 定义含有类型转换运算符的类
      • 显式的类型转换运算符
    • 避免有二义性的类型转换

基本概念

如果一个运算符函数是成员函数,则它的第一个(左侧)运算对象绑定到隐式的this指针上,因此,成员运算符函数的(显式)参数数量比运算符的运算对象总数少一个。

对于一个运算符函数来说,它或者是类的成员,或者至少含有一个类类型的参数:

错误,不能为int重定义内置的运算符
int operator+(int,int);

我们可以重载大多数运算符,但不是全部。我们只能重载已有的运算符,而无权发明新的运算符号。
在这里插入图片描述
对于一个重载的运算符来说,其优先级和结合律与对应的内置运算符保持一致。

直接调用一个重载的运算符函数

一个非成员运算符函数的等价调用

data1+data2; //普通的表达式
operator+(data1,data2); // 等价的函数调用

调用成员运算符函数

data1+=data2; //基于“调用”的表达式
data1.operator+=(data2); // 对成员运算符函数的等价调用

某些运算符不应该被重载

通常情况下,不应该重载逗号、取地址、逻辑与、逻辑或等运算符。

使用与内置类型一致的含义

在这里插入图片描述

选择作为成员或者非成员

当我们定义重载的运算符时,必须首先决定是将其声明为类的成员函数还是声明为一个普通的非成员函数。在某些时候我们别无选择,因为有的运算符必须作为成员;另一些情况下,运算符作为普通函数比作为成员更好。
在这里插入图片描述

%通常定义为非成员
%=通常定义为类成员,因为它会改变对象的状态
++通常定义为类成员,因为它会改变对象的状态
->必须定义为类成员,否则编译会报错
<<通常定义为非成员
&&通常定义为非成员
==通常定义为非成员
()必须定义为类成员,否则编译会报错

输入和输出运算符

IO标准库分别使用>>和<<执行输入和输出操作。对于这两个运算符来说,IO库定义了用其读写内置类型的版本,而类则需要自定义适合其对象的新版本以支持IO操作。

重载输出运算符<<

通常情况下,输出运算符的第一个形参是一个非常量ostream对象的引用。之所以ostream是非常量是因为向流写入内容会改变其状态,而该形参是引用是因为我们无法直接复制一个ostream对象。

第二个形参一般来说是一个常量的引用,该常量是我们想要打印的类类型。第二个形参是引用的原因是我们希望避免复制实参,而之所以该形参可以是常量是因为(通常情况下)打印对象不会改变对象的内容。
为了与其他输出运算符保持一致,operator<<一般要返回它的ostream形参。

示例代码:

ostream& operator<<(ostream&os,const Sales_data &item){//输出内容os<<item.isbn()<<" "<<item.units_sold;//返回ostreamreturn os;
}

输出运算符尽量减少格式化操作

用于内置类型的输出运算符不太考虑格式化操作,尤其不会打印换行符,用户希望类的输出运算符也像如此行事。如果运算符打印了换行符,则用户就无法在对象的同一行内接着打印一些描述性的文本了。相反,令输出运算符尽量减少格式化操作可以使用户有权控制输出的细节。

输入输出运算符必须是非成员函数

与iostream标准库兼容的输入输出运算符必须是普通的非成员函数,而不能是类的成员函数。否则,它们的左侧运算对象将是我们的类的一个对象:

Sales_data data;
data<<cout; //如果operator<<是Sales_data的成员

因此,如果我们希望为类自定义IO运算符,则必须将其定义为非成员函数。IO运算符通常需要读写类的非公有数据成员,所以IO运算符一般被声明为友元。

重载输入运算符>>

通常情况下,输入运算符的第一个形参是运算符将要读取的流的引用,第二个形参是将要读入到的(非常量)对象的引用。该运算符通常会返回某个给定流的引用。 第二个形参之所以必须是个非常量是因为输入运算符本身的目的就是将数据读入到这个对象中。

输入运算符必须处理输入可能失败的情况,而输出运算符不需要。

输入时的错误:

  • 当流含有错误类型的数据时读取操作可能失败。
  • 当读取操作到达文件末尾或者遇到输入流的其他错误时也会失败。

通常情况下,输入运算符只设置failbit。除此之外,设置eofbit表示文件耗尽,而设置badbit表示流被破坏。

算术和关系运算符

通常,我们把算术和关系运算符定义成非成员函数以允许对左侧或右侧的运算对象进行转换。因为这些运算符一般不需要改变运算对象的状态,所以形参都是常量的引用。

算术运算符通常会计算它的两个运算对象并得到一个新值,这个值有别于任意一个运算对象,常常位于一个局部变量之内,操作完成后返回该局部变量的副本作为其结果。如果类定义了算术运算符,则它一般也会定义一个对应的复合赋值运算符。此时最有效的方式是使用复合赋值来定义算术运算符:

Sales_data operator+(const Sales_data &lhs,const Sales_data &rhs){Sales_data sum = lhs;//把lhs的数据成员拷贝给sumsum+=rhs; //使用复合赋值运算符将rhs加到sum中return sum;
}

如果类同时定义了算术运算符和相关的复合赋值运算符,则通常情况下应该使用复合赋值来实现算术运算符。

相等运算符

通常情况下,c++中的类通过定义相等运算符来检验两个对象是否相等。也就是说,它们会比较对象的每一个数据成员,只有当所有对应的成员都相等时才认为两个对象相等。

关系运算符

定义了相等运算符的类也常常(但不总是)包括关系运算符。特别是,因为关联容器和一些算法要用到小于运算符,所以定义operator<会比较有用。

通常情况下,关系运算符应该:

  • 定义顺序关系,令其与关联容器中对关键字的要求一致。
  • 如果类同时也含有 == 运算符的话,则定义一种关系令其与 == 保持一致。特别是,如果两个对象是 != 的,那么一个对象应该 < 另外一个。

如果存在唯一一种逻辑可靠的 < 定义,则应该考虑为这个类定义 < 运算符。如果类同时还包含 == ,则当且仅当 < 的定义和 == 产生的结果一致时才定义 < 运算符。

赋值运算符

我们可以重载赋值运算符,不论形参的类型是什么,赋值运算符都必须定义为成员函数。

示例代码:
在这里插入图片描述

复合赋值运算符

复合赋值运算符不非得是类的成员,不过我们还是倾向于把包括复合赋值在内的所有赋值运算都定义在类的内部。为了与内置类型的复合赋值保持一致,类中的复合赋值运算符也要返回其左侧运算对象的引用。

示例代码:
在这里插入图片描述
赋值运算符必须定义成类的成员,复合赋值运算符通常情况下也应该这样做。这两类运算符都应该返回左侧运算对象的引用。

下标运算符

表示容器的类通常可以通过元素在容器中的位置访问元素,这些类一般会定义下标运算符operator[ ]。

下标运算符必须是成员函数。

为了与下标的原始定义兼容,下标运算符通常以所访问元素的引用作为返回值,这样做的好处是下标可以出现在赋值运算符的任意一端。进一步,我们最好同时定义下标运算符的常量版本和非常量版本,当作用于一个常量对象时,下标运算符返回常量引用以确保我们不会给返回的对象赋值

示例代码:
在这里插入图片描述

递增和递减运算符

定义递增和递减运算符的类应该同时定义前置版本和后置版本。这些运算符通常应该被定义成类的成员。

为了与内置版本保持一致,前置运算符应该返回递增或递减后对象的引用。
在这里插入图片描述
在这里插入图片描述

区分前置和后置运算符

前置和后置版本使用的是同一个符号,意味着其重载版本所用的名字将是相同的,并且运算对象的数量和类型也相同。为了解决这个问题,后置版本接受一个额外的(不被使用的)int类型的形参。当我们使用后置运算符时,编译器为这个形参提供一个值为0的实参。尽管从语法上来说,后置函数可以使用这个额外的形参,但是在实际过程中通常不会这么做。这个形参的唯一作用就是区分前置版本和后置版本的函数,而不是真的要在实现后置版本时参与运算。

为了与内置版本保持一致,后置运算符应该返回对象的原值(递增或递减之前的值),返回的形式是一个值而非引用。

后置版本示例代码:
在这里插入图片描述

显式地调用后置运算符

StrBlobPtr p(a1);
p.operator++(0);  //调用后置版本的operator++
p.operator++();   //调用前置版本的operator++

成员访问运算符

箭头运算符 -> 必须是类的成员。解引用运算符 * 通常也是类的成员。

重载的箭头运算符必须返回类的指针或者自定义了箭头运算符的某个类的对象。

函数调用运算符

如果类重载了函数调用运算符,则我们可以像使用函数一样使用该类的对象。因为这样的类同时也能存储状态,所以与普通函数相比它们更加灵活。

函数调用运算符必须是成员函数,一个类可以定义多个不同版本的调用运算符,相互之间应该在参数数量或类型上有所区别。

如果类定义了调用运算符,则该类的对象称作函数对象。因为可以调用这种对象,所以我们说这些对象的“行为像函数一样”。

class absInt{int operator()(int val)const{return val < 0 ? -val : val;}
}int i=-42;
absInt absObj;		//含有函数调用运算符的对象
int ui = absObj(i);  //将i传递给absObj.operator()

即使absObj只是一个对象而非函数,我们也能“调用”该对象。调用对象实际上是在运行重载的调用运算符。该例中,该运算符接受一个int值并返回其绝对值。

含有状态的函数对象类

和其他类一样,函数对象类除了operator()之外也可以包含其他成员。函数对象类通常含有一些数据成员,这些成员被用于定制调用运算符中的操作。

示例代码:

#ifndef PRINTSTRING_H
#define PRINTSTRING_H#include<iostream>
#include<string>
using namespace std;class PrintString
{
public:PrintString(ostream &o=cout,char c=' ') :os(o),sep(c){}void operator()(const string &s)const { os << s << sep; }
private:ostream &os;char sep;
};
#endif

测试代码:

void testPrintString() {PrintString p1;p1("hello");PrintString p2(cout, '!');p2("hello");
}

输出结果:

hello hello!

示例代码:

//IntCompare类
class IntCompare {
public:IntCompare(int v) :val(v) {}bool operator()(int v) { return val == v; }
private:int val;
};//测试代码vector<int>vec = { 1,2,3,2,1 };int oldVal = 2;int newVal = 200;IntCompare icmp(oldVal);replace_if(vec.begin(),vec.end(),icmp,newVal);for (auto a:vec) {cout << a << " ";}

输出结果:

1 200 3 200 1

lambda是函数对象

在lambda表达式产生的类中含有一个重载的函数调用运算符,例如:

[](const string & a , const string & b){return a.size()<b.size();}

其行为类似于下面这个类的一个未命名对象:

class ShortString{
public:bool operator()(const string & a , const string & b)		{return a.size()<b.size();}
}

该类可被如下调用:

stable_sort(words.begin(),words.end(),ShortString());

当stable_sort内部的代码每次比较两个string时就会“调用”这一对象,此时该对象将调用运算符的函数体,判断第一个string的大小小于第二个时返回true。

表示lambda及相应捕获行为的类

当一个lambda表达式通过引用捕获变量时,将由程序负责确保lambda执行时引用所引的对象确实存在。因此编译器可以直接使用该引用而无须在lambda产生的类中将其存储为数据成员。

如果通过值捕获的变量被拷贝到lambda中,这种lambda产生的类必须为每个值捕获的变量建立对应的数据成员,同时创建构造函数,令其使用捕获的变量的值来初始化数据成员。

示例如下:

[sz](const string & a){return a.size()>=sz;}

该lambda表达式产生的类将形如:

class SizeComp{
public:SizeComp(size_t n):sz(n){}  //该形参对应捕获的变量//该调用运算符的返回类型、形参和函数体都与lambda一致bool operator(){const string & s}const{return s.size()>=sz;}
private:size_t sz;//该数据成员对应通过值捕获的变量
}

这个类含有一个数据成员以及一个用于初始化该成员的构造函数。这个合成的类不含有默认构造函数,因此要想使用这个类必须提供一个实参:

auto wc = find_if(words.begin(),words.end(),SizeComp(sz));

lambda表达式产生的类不含默认构造函数、赋值运算符及默认析构函数;它是否含有默认的拷贝 / 移动构造函数则通常要视捕获的数据成员类型而定。

标准库定义的函数对象

标准库定义了一组表示算术运算符、关系运算符和逻辑运算符的类,每个类分别定义了一个执行命名操作的调用运算符。例如,plus类定义了一个函数调用运算符用于对一对运算对象执行+的操作;modulus类定义了一个调用运算符执行二元的%操作;equal_to类执行==。
示例代码

	plus<int>intAdd;negate<int>intNegate;//negate<int>可对int取反int sum = intAdd(10,20);cout << sum << endl;sum = intNegate(intAdd(10, 20));cout << sum << endl;sum = intAdd(10, intNegate(20));cout << sum << endl;

输出结果:

30
-30
-10

标准库函数对象,下表所列的类型定义在functional头文件中
在这里插入图片描述

在算法中使用标准库函数对象

表示运算符的函数对象常用来替换算法中的默认运算符。例如,默认情况下,排序算法使用operator<将序列按照升序排列,如果要执行降序排列的话,我们可以传入一个greater类型的对象。该类将产生一个调用运算符并负责执行待排序类型的大于运算。例如,如果svec是一个vector<string>

sort(svec.begin(),svec.end(),greater<string>());

示例代码:

	vector<int>vec{ 1,3,5,7,9,2,4,6,8,10 };//统计大于4的值有多少个int num = count_if(vec.begin(),vec.end(),bind2nd(greater<int>(),4));cout << num << endl;vector<string>sv{"hello","hello","hi","nihao","nihao"};//找到第一个不等于hello的字符串auto its = find_if(sv.begin(),sv.end(), bind2nd(not_equal_to<string>(), "hello"));cout << *its << endl;//将所有的值乘以2transform(vec.begin(), vec.end(), vec.begin(), bind2nd(multiplies<int>(), 2));for (auto a:vec) {cout << a << " ";}cout << endl;

输出结果:

6
hi
2 6 10 14 18 4 8 12 16 20

transform函数

transform函数的作用是:将某操作应用于指定范围的每个元素。transform函数有两个重载版本:

transform(first,last,result,op);
first是容器的首迭代器,last为容器的末迭代器,result为存放结果的容器,op为要进行操作的一元函数对象或sturct、class。

transform(first1,last1,first2,result,binary_op);
first1是第一个容器的首迭代 器,last1为第一个容器的末迭代器,first2为第二个容器的首迭代器,result为存放结果的容器,binary_op为要进行操作的二元函数 对象或sturct、class。

可调用对象与function

c++语言中有几种可调用的对象:函数、函数指针、lambda表达式、bind创建的对象以及重载了函数调用运算符的类。

和其他对象一样,可调用的对象也有类型。例如,每个lambda有它自己唯一的(未命名)类类型;函数及函数指针的类型则由其返回值类型和实参类型决定,等等。

不同类型可能具有相同的调用形式

在这里插入图片描述
上面这些可调用对象分别对其参数执行了不同的算术运算。尽管它们的类型各不相同,但是共享同一种调用形式:int(int,int)

我们可以定义一个函数表用于存储指向这些可调用对象的“指针”。当程序需要执行某个特定的操作时,从表中查找该调用的函数。

函数表可以很容易的通过map来实现。我们的map可以定义成如下形式:

//构建从运算符到函数指针的映射关系,其中函数接受两个int、返回一个int
map<string,int(*)(int,int)>binops;

我们可以按照下面的形式将add的指针添加到binops中:

binops.insert({"+",add});//{"+",add}是一个pair

但是我们不能将mod或者divide存入binops中,因为mod是个lambda表达式,而每个lambda有它自己的类类型,该类型于存储在binops中的类型不匹配。

binops.insert({"%",mod});//错误:mod不是一个函数指针

我们可以使用一个名为function的新的标准库类型解决上述问题,function定义在functional头文件中,下表列出了function定义的操作:
在这里插入图片描述
function是一个模板,和我们使用过的其他模板一样,当创建一个具体的function类型时我们必须提供额外的信息。示例如下:

function<int(int,int)>

在这里我们声明了一个function类型,它可以表示接受两个int、返回一个int的可调用对象。

function<int(int,int)>f1 = add;
function<int(int,int)>f1 = divide();
function<int(int,int)>f1 = [](int i,int j){return i*j};//f1(4,2): 6
//f2(4,2): 2
//f3(4,2): 8

使用这个function我们可以重新定义map:

map<string,function<int(int,int)>>binops;

我们能把所有可调用对象,包括函数指针、lambda或者函数对象在内,都添加到这个map中:

map<string,function<int(int,int)>>binops={
{"+",add}, 					 		 //函数指针
{"-",std::minus<int>()}, 			 //标准库函数对象
{"/",divide()},						 //用户定义的函数对象
{"*",[](int i,int j){return i*j}},	 //未命名的lambda
{"%",mod},							 //命名的lambda
}

调用操作:

binops["+"](10,5); //调用add(10,5)

重载的函数与function

我们不能(直接)将重载函数的名字存入function类型的对象中。
在这里插入图片描述

重载、类型转换与运算符

类型转换运算符

类型转换运算符是类的一种特殊成员函数,它负责将一个类类型的值转换成其他类型。类型转换函数的一般形式如下所示:

operator type()const;

其中type表示某种类型。类型转换运算符可以面向任意类型(除了void之外)进行定义,只要该类型能作为函数的返回类型。因此我们不允许转换成数组或者函数类型,但允许转换成指针(包括数组指针及函数指针)或者引用类型。

一个类型转换函数必须是类的成员函数;它不能声明返回类型,形参列表也必须为空。类型转换函数通常应该是const。

定义含有类型转换运算符的类

class SmallInt {
public:SmallInt(int i = 0) :val(i) {}operator int()const { return val; }void print() { cout << val << endl; }
private:size_t val;
};//测试代码:SmallInt s1;s1 = 4;s1.print();cout << s1 + 5 << endl;s1 = 3.5;s1.print();cout << s1 + 5 << endl;

输出结果:

4
9
3
8

因为类型转换运算符是隐式执行的,所以无法给这些函数传递实参,当然也就不能在类型转换运算符的定义中使用任何形参。同时,尽管类型转换函数不负责指定返回类型,但实际上每个类型转换函数都会返回一个对应类型的值:
在这里插入图片描述

显式的类型转换运算符

当类型转换运算符是显式的时候,我们也能执行类型转换,不过必须通过显式的强制类型转换才可以。

class SmallInt {
public:SmallInt(int i = 0) :val(i) {}explicit operator int()const { return val; }void print() { cout << val << endl; }
private:size_t val;
};//测试代码SmallInt s1;s1 = 4;s1.print();cout << int(s1) + 5 << endl;s1 = 3.5;s1.print();cout << int(s1) + 5 << endl;

如果表达式被用作条件,则编译器会将显式的类型转换自动应用于它。换句话说,当表达式出现在下列位置时,显式的类型转换将被隐式地执行:
在这里插入图片描述

向bool的类型转换通常用在条件部分,因此operator bool一般定义成explicit的。

避免有二义性的类型转换

如果类中包含一个或多个类型转换,则必须确保在类类型和目标类型之间只存在唯一一种转换方式。否则的话,我们编写的代码很可能会具有二义性。

在两种情况下,可能产生多重转换路径。

  • 两个类提供相同的类型转换,例如,当A类定义了一个接受B类对象的转换构造函数,同时B类定义了一个转换目标是A类的类型转换运算符时,我们就说它们提供了相同的类型转换。
    在这里插入图片描述
  • 类定义了多个转换规则,而这些转换涉及的类型本身可以通过其他类型转换联系在一起。最典型的例子是算术运算符,对某个给定的类来说,最好只定义最多一个与算术类型有关的转换规则。
    在这里插入图片描述

除了显式地向bool类型的转换之外,我们应该尽量避免定义类型转换函数并尽可能地限制那些“显然正确”的非显式构造函数。

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

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

相关文章

C语言 回调函数 produce(arr,len,getRand)

基本介绍 回调函数:形参中包含另一个函数的函数指针 用函数指针接收另一个函数 案例 代码解析 具体代码 #include<stdio.h> #include<stdlib.h> //回调函数--//函数原型 int getRand(); int *produce(int*arr,int len,int(*get)()); int main() {int arr[10…

C语言 动态内存分配机制(堆区) int*p=malloc(5*sizeof(4))

C程序内存分配图 栈区:局部变量 堆区:动态分配的数据 静态存储区/全局区:全局变量,静态数据 代码区:代码,指令 内存分配说明 内存动态分配的相关函数 堆区: #inlcude<stdlib.h> Malloc(size);//分配长度为size个字节的连续空间 Calloc(n,size);//分配size个长度为n…

C语言 结构体 struct Cat cat1;

引入 使用传统技术解决 需要定义多个变量或数组 结构体与结构体变量的关系示意图 类似Java类中的对象(结构体)与属性(结构体变量) 一切物体都可以看作对象(结构体) 补充:C语言数据类型 简单使用案例 代码 Cat是我们自己定义的数据类型 struct Cat cat1;//创建struct Cat的…

C语言 共用体/联合体 union

引入 传统技术的缺陷—结构体 共用体基本介绍 共用体与结构体一样都是值传递 定义共用体的三种方式 内存布局 共用体数据空间占用最大的成员的数据空间大小 案例解析 1) 2) 3) 4) 注: 1010 1101 0101 0100所对应的十进制是负数 计算机中的二进制都是以补码存储的,所…

C语言 项目练习-家庭收支软件

目标 需求说明 界面说明 登记收入界面: 登记支出界面 收支明细界面 退出界面 项目代码改进要求 自己完成的代码 版本1 #include<stdio.h> #include<string.h> void choose(int button,int i); //项目--家庭收支软件 static double total10000;//总金额 #de…

c++ fmt 库安装和使用示例、clion配置

安装 git clone https://github.com/fmtlib/fmt.gitmake .mkae && make install CLion使用 使用和安装存在出入下载源码&#xff0c;可以先 clone 到你的项目中去&#xff0c;https://github.com/fmtlib/fmt &#xff0c;我放到的是项目的 dependencies 目录然后在…

C语言 项目 CRM系统(客户信息管理系统)

项目目标 项目需求说明 系统界面 1)添加客户界面 通过编号来区分客户 2)删除客户界面 对用户输入的编号进行核查,存在与否,合法与否 3)显示客户列表界面 4)修改客户信息的界面 项目设计 Customer结构体的设计 CRM系统结构框架图 案例代码 #include <stdio.h>…

代码重构 防火墙 相关知识

参考 依据Linux命令以及sysconf下现有的iptables命令&#xff0c;详见hsm_sysconf_server/src/sysconf_server.cpp中的firewall规则。 接口名称 firewall_manager 目的(现实) 根据网口直连获取当前eth0和eth1的各种信息保证设置的正确性 以及要针对管理口和服务口设计不…

C语言 文件的基本介绍

基本介绍 输入流与输出流 重点在C程序(内存)的数据移动方向 对于C程序(内存) 输入数据:输入流 输出数据:输出流 输入 和输出 C标准库 标准输入输出库 标准文件 getchar()&putchar()函数 代码 #include<stdio.h> #include<stdlib.h> //文件--getchar()和…

ubuntu修改字体 样式

使用 快捷键 ctrlaltt 打开终端安装gnome-tweaks桌面管理工具 sudo apt install gnome-tweaksaltf2 在运行窗口输入 gnome-tweaks 命令&#xff0c;然后回车打开优化窗口&#xff0c;选择第二个front字体选项ubuntu显示中文

C语言 文件的读写

引入 OS操作系统 打开文件fopen()函数 读写模式: r:读取已有文件 w:文件不存在,创建文件并写入文件.文件存在,内容清零,再写入文件 a: 文件不存在,创建文件并写入文件.文件存在,以追加的形式写入文件 r:读写已有文件 w:文件不存在,创建文件并读写文件.文件存在,内容清零,再…

StarWind V2V Image Converter:虚拟机镜像转换工具,可将 IMG 文件转换为 VMware VMDK 文件

操作流程 选择本地的需要转换的文件找到源文件的路径&#xff0c;img格式选择转化后的格式 第一个选择 第二个 速度快一些选择将转化后的文件的存储路径软件的下载链接 链接: https://pan.baidu.com/s/1Fe6yI42Zz9d_Q7aUhGe1FQ 提取码: 5vmv

数学建模基础知识

原型与模型 模型的分类 数学建模 数学建模的分类 成为建模大神 数学建模比赛 数学建模一般步骤 数学建模全过程 数学建模论文写作 1&#xff09;摘要:是决定最后获奖等级的关键 2&#xff09;问题重述:使用自己的语言将问题重述一次 3&#xff09;符号说明:对于常见的或…

数学建模 线性规划模型基本原理

线性规划问题 例1.1 可行解&可行域 matlab标准形式及软件求解 标准形式: C称为价值向量 如果是求max,加一个负号-c^T 如果是求Ax>b,加一个负号-Ax<b 使用matlab求线性规划例题 求解的是最大值:加上负号 y是求解的最优解 zeros()使用: zeros(n)&#xff1a;生…

接上文 ,解决 虚拟机VM,U盘(磁盘)装有系统,将其中系统安装到另外一块磁盘的具体操作

问题原因&#xff1a;接上文&#xff0c;将生成的vsdk格式的磁盘导入VM创建镜像&#xff0c;相关于U盘装载系统镜像&#xff0c;将U盘其中的镜像导入到磁盘里边&#xff0c;U盘是引导&#xff0c;会将系统最终装载到磁盘出错原因是因为 没有新建第二块磁盘 解决 新增一块磁盘如…

数学建模 层次分析法

简介 针对多目标,多准则或无结构特性的复杂决策问题 步骤 解决评价类问题 评价类问题: 资料查找: 1)查找相关文献 2)如果没有找到相关文献 3)搜索 通过上述步骤后得到的结果 构建层次结构模型 举例: 成对比较矩阵 标度表: 奇数:越大越重要 偶数:上述两相邻判断的中值…

接上文 VM安装的ubuntu系统,配置双网卡

点击编辑 进入虚拟网络编辑器 点击更改设置 补充&#xff1a;如何判定桥接至哪张网卡&#xff1f;进入win&#xff0c;winr 输入cmd&#xff1b;输入 systeminfo选中系统&#xff0c;点击右键&#xff0c;选中设置 重启系统使用 ifconfig查看&#xff0c;发现有eth0和eth1…

数学建模 趣味数模问题(数模入门)

狼羊人菜渡河问题 解答 试探法 因为有4个变量,所以一共有222*216种状态 找出其中不安全的状态:无人看守的状态下:狼羊一起,羊菜一起 人 狼 羊 菜(0是在对面,1是在这边) 狼羊一起:(0,1,1,0) (0,1,1,1) (1,0,0,0) (1,0,0,1) 羊菜一起:(0,0,1,1) (1,1,0,0) 其余的10个都是安全状态…

数学建模 整数规划的基本原理和标准形式

整数规划模型 变量限制为整数 一般解决运输问题和整数问题 分类: 研究的是纯整数规划问题 整数规划特点 实数的解不能直接四舍五入为整数,因为此时可能不满足约束条件 举例-合理下料问题 模型: 题目: 这是在使用材料 1)使用零件A1-Am毛胚,就是使用零件 2)下料方式B1-Bn就…