初识C++ - 类与对象(中篇·下半)

news2024/11/20 11:44:22

目录

赋值运算符重载

以下是一个日期类的运算符重载的案例(重点)

关于流插入与流提取的使用

方法一:定义与声明分离 

方法二:使用内联函数

const成员

概念 

关于上述日期类代码为什么需要在函数后面加入const 

取地址及const取地址操作符重载

结束语


以下是对上半的补录 -- 补充一点细节

赋值运算符重载

赋值运算符重载格式
参数类型 const T& ,传递引用可以提高传参效率
返回值类型 T& ,返回引用可以提高返回的效率,有返回值目的是为了支持连续赋值
检测是否自己给自己赋值
返回 *this :要复合连续赋值的含义

赋值构造(和拷贝构造很类似,但是有区别)

	//拷贝构造函数(默认生成的是浅拷贝 - 在一些情况(有动态内存开辟的)下是不够用的)
	Date(const Date& d)
	{
		_year = d._year;
		_month = d._month;
		_day = d._day;
	}
	//上下两个很像,但是有区别,意义不一样
	//赋值重载
	void operator=(const Date& d)
	{
		_year = d._year;
		_month = d._month;
		_day = d._day;
	}
//测试赋值重载与拷贝构造的区别
void TestDate2()
{
	Date d1;
	Date d2(2022, 10, 11);

	Date d3(d2); //拷贝构造(初始化)  一个拷贝初始化另一个马上要创建的对象
	Date d4 = d2;	//这里是一个拷贝构造,要看意义
		
	d1.print();	// 赋值重载(也是默认构造函数,没有写会自动生成一个)
	d1 = d2;	// 赋值重载(复制拷贝) 已经存在两个对象之间拷贝
	d1.print();
}

但是以上的写法是不支持连续赋值的,但是连续赋值确实我们经常使用的,比如我们写的

int i ,j; i = j = 10;          //但是上面的写法是不支持这样用的,为此我们需要再改进一步

	//拷贝构造函数(默认生成的是浅拷贝 - 在一些情况(有动态内存开辟的)下是不够用的)
	Date(const Date& d)
	{
		_year = d._year;
		_month = d._month;
		_day = d._day;
	}
	//上下两个很像,但是有区别,意义不一样
	//赋值重载
	Date& operator=(const Date& d)
	{
		_year = d._year;
		_month = d._month;
		_day = d._day;

		return *this;	//传值返回(代价大),会调用一次拷贝构造,所以不要这样写
						//但是我们需要注意这里的 *this 所指的对象还在不在,this会销毁,因为函数出了作用域自动就销毁了
		
		//return d;     //理论上是可以返回d的(值一样),但是由于权限的放大就会报错,除非在函数的最前端加上 const 
						//但是一旦加上了const,就会导致这样的玩法不行 (i = j = 10)++ ,我们需要让它的返回值是可以进行修改的(左值)
						//正常情况下都是返回 操作符 左边那一个数
	}

栈上面的赋值重载需要自己写(有动态内存的开辟)

原因 

正确的栈的赋值重载

//深拷贝
typedef int DataType;
class Stack
{
public:
	//构造函数
	Stack(size_t capacity = 4)
	{
		_array = (DataType*)malloc(capacity * sizeof(DataType));
		if (nullptr == _array)
		{
			perror("malloc申请空间失败");
			return;
		}
		_size = 0;
		_capacity = capacity;
	}
	void Push(const DataType& data)
	{
		_array[_size] = data;
		_size++;
	}

	//拷贝构造 -- 深拷贝
	Stack(const Stack& st)
	{
		_array = (DataType*)malloc(sizeof(DataType) * st._capacity);
		if (nullptr == _array)
		{
			perror("malloc申请空间失败");
			exit(-1);
		}
		memcpy(_array, st._array, sizeof(DataType) * st._size);	//利用memcpy进行拷贝,利用 st._size(数据的个数)更好点

		_size = st._size;
		_capacity = st._capacity;
	}

	//Stack(有动态内存开辟) 需要自己写一个赋值重载,默认生成的是不行滴!
	Stack& operator=(const Stack& st)
	{
		if ( this != &st)	//要加一层判断
		{
			//为防止这样写 st1 = st1 (自己给自己赋值,语法上是通过的,但是会致使_array的值变为随机值了,因为一开始就free掉了)
			//但是还是在用,造成了越界访问(访问已经释放掉的空间,所以会是随机值)
			free(_array);	//这里是不能free(this)的,因为this是* const(在星的右边)类型的,本身是不能被修改的

			_array = (DataType*)malloc(sizeof(DataType) * st._capacity);
			if (nullptr == _array)
			{
				perror("malloc申请空间失败");
				exit(-1);
			}
			memcpy(_array, st._array, sizeof(DataType) * st._size);	//利用memcpy进行拷贝,利用 st._size(数据的个数)更好点
			_size = st._size;
			_capacity = st._capacity;

		}

		return *this;
	}

	//析构函数
	~Stack()
	{
		if (_array)
		{
			free(_array);
			_array = nullptr;
			_capacity = 0;
			_size = 0;
		}
	}
private:
	DataType* _array;
	size_t _size = 0;
	size_t _capacity = 0;
};

以下是一个日期类的运算符重载的案例(重点)


Date.h(声明)

#pragma once
#include <iostream>
using std::endl;
using std::cout;
using std::cin;
using std::ostream;
using std::istream;
//using namespace std;



//以下为一个声明与定义分离的日期类写法
/


class Date
{
public:
	// 全缺省的构造函数
	Date(int year = 1, int month = 1, int day = 1)
	{
			_year = year;
			_month = month;
			_day = day;
		//检查日期是否合法 -- 这里考虑的并不是很完全
		if (!(_year >= 1
			&& (_month >= 1 && _month <= 12)
			&& (_day>=1 && _day<= GetMonthDay(year, month))))
		{
			cout << "非法日期" << endl;
		}
	}

	//赋值重载
	Date& operator=(const Date& d)
	{
		if (this != &d) //理论上加上好一点(防止自己给自己赋值),但是日期类用默认赋值函数就好了
		{
			_year = d._year;
			_month = d._month;
			_day = d._day;
		}

		return *this;	//传值返回(代价大),会调用一次拷贝构造,所以不要这样写
						//但是我们需要注意这里的 *this 所指的对象还在不在,this会销毁,因为函数出了作用域自动就销毁了

	}

	// 获取某年某月的天数
	int GetMonthDay(int year, int month)
	{
		static int monthDayArray[13] = { 0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 };	//使用静态的就不需要反复创立数组,造成浪费了,当然最好的方式是定义于声明分离
		if (month == 2 && ((year % 4 == 0 && year % 100 != 0) || year % 400 == 0))
		{
			return 29;
		}
		else
		{
			return monthDayArray[month];
		}
	}

	//打印
	void Print() const	//C++是允许在这里加const的,用以修饰 *this 指针,其他的参数是不受影响的
	{
		cout << _year << "/" << _month << "/" << _day << endl;
	}



	Date& operator+=(int day);	

	Date operator+(int day) const;	

	Date operator-(int day) const;

	Date& operator-=(int day);

	Date& operator++();

	Date operator++(int);

	Date operator--(int);

	Date& operator--();

	bool operator==(const Date& d) const;

	bool operator>=(const Date& d) const;

	bool operator>(const Date& d) const;

	bool operator<(const Date& d) const;

	bool operator<=(const Date& d) const;

	bool operator!=(const Date& d) const;

	int operator-(const Date& d) const;

	//友元函数可以声明在类的任意位置
	//friend ostream& operator<<(ostream& out, const Date& d);
	//friend istream& operator>>(istream& in, Date& d);	

	friend inline ostream& operator<<(ostream& out, const Date& d);
	friend inline istream& operator>>(istream& in, Date& d);	

private:
	int _year;
	int _month;
	int _day;
};

Date.cpp(定义)

#include "Date.h"

//以下为一个声明与定义分离的日期类写法
/

//等于 ==
bool Date::operator==(const Date& d) const
{
	return _year == d._year		//_year 前面默认有一个 this指针,下面同理 
		&& _month == d._month
		&& _day == d._day;
}

//大于  >
bool Date::operator>(const Date& d) const
{
	if (_year > d._year)
	{
		return true;
	}
	else if (_year == d._year && _month > d._month)
	{
		return true;
	}
	else if (_year == d._year && _month == d._month && _day > d._day)
	{
		return true;
	}
	return false;
}

//大于等于 >=
bool Date::operator>=(const Date& d) const
{
	return  *this > d || *this == d;	//所以类里面是允许使用 this指针 的,因为有需求
}

//小于等于 <=
bool Date::operator <= (const Date& d) const
{
	return  *this < d || *this == d;
}

// 小于 <
bool Date::operator < (const Date& d) const
{
	return !(*this >= d);
}

// 不等于 !=
bool Date::operator != (const Date& d) const
{
	return !(*this == d);
}

// 加等 +=
Date& Date::operator+=(int day)	//需要传引用返回
{
	//加一层判断
	if (day < 0)
	{
		return *this -= abs(day);
	}

	_day += day;
	while (_day > GetMonthDay(_year, _month))
	{
		_day -= GetMonthDay(_year, _month);
		_month++;

		if (_month == 13)
		{
			++_year;
			_month = 1;
		}
	}
	return *this;	//应该用引用返回,传值返回会有一个拷贝
}


//加 +
Date Date::operator+(int day) const	//要使用单纯的传值返回了,就好比  3(a) + 2 = 5; 这里的a的值是不变的
{
	Date ret(*this);
	ret += day;
	return ret;		//传值返回
}


//减等 -=
Date& Date::operator-=(int day)
{
	if (day < 0)
	{
		//return *this -= -day;
		return *this += abs(day);
	}

	_day -= day;
	while (_day <= 0)
	{
		--_month;
		if (_month == 0)
		{
			--_year;
			_month = 12;
		}

		_day += GetMonthDay(_year, _month);
	}

	return *this;
}

// 减 -
Date Date::operator-(int day) const	//日期减 天数
{
	Date ret(*this);
	ret -= day;
	return ret;		//传值返回	
}

// 前置++
Date& Date::operator++()
{
	return *this += 1;
}

// 后置++
Date Date::operator++(int)	//关于为什么是 int 这是在创建好时候约定的,没有为什么
{
	Date tmp(*this);
	*this += 1;
	return tmp;		//传值返回	
}

// 后置--
Date Date::operator--(int)	//关于后置为什么多一个返回值,也是约定的,没有为什么
{
	Date ret(*this);
	*this -= 1;
	return ret;		//传值返回	
}

// 前置--
Date& Date::operator--()		//通过这里我们也可以知道,关于用前置++(--),还是后置++(--)的选择,后置需要拷贝
{								//当然这里是自定义类型回如此,内置类型是不会这样的,不过即使这样还是推荐使用前置的
	return *this -= 1;
}

// 日期减日期 -
int Date::operator-(const Date& d) const
{
	Date max = *this;
	Date min = d;		//只有引用与指针才可能导致权限的放大与缩小
	int flag = 1;

	if (*this < d)
	{
		max = d;
		min = *this;
		flag = -1;
	}
	
	int n = 0;
	while (min != max)
	{
		++n;
		++min;
	}
	return n * flag;
}


///

//方法一:定义与声明分离
流插入 <<
//ostream& operator<<(ostream& out, const Date& d)
//{
//	out << d._year << "年" << d._month << "月" << d._day << endl;
//	return out;
//}
//
流提取 >>
//istream& operator>>(istream& in, Date& d)//这里就不用加const,因为需要该d里面的值
//{
//	in >> d._year >> d._month >> d._day;
//	return in;
//}

以下是测试案例

#include "Date.h"

//以下为一个声明与定义分离的日期类写法的测试
/

void TestDate1()
{
	Date d1(2022, 10, 8);
	Date d3(d1);
	Date d4(d1);

	d1 -= 10000;
	d1.Print();

	Date d2(d1);
	/*Date d3 = d2 - 10000;d3.Print();*/

	(d2 - 10000).Print();	//甚至可以这样只写
	d2.Print();

	d3 -= -10000;
	d3.Print();

	d4 += -10000;
	d4.Print();
}

void TestDate2()
{
	Date d1(2022, 10, 8);
	Date d2(d1);
	Date d3(d1);
	Date d4(d1);

	(++d1).Print(); // d1.operator++()	这里要考虑运算符的优先级
	d1.Print();

	(d2++).Print(); // d1.operator++(1)
	d2.Print();
}



void TestDate3()
{
	Date d1(2022, 10, 10);
	Date d2(2023, 7, 1);

	cout << d2 - d1 << endl;
	cout << d1 - d2 << endl;
}

void TestDate4()
{
	Date d1, d2;
	//cin >> d1;  // 流提取
	//cout << d1;   // 流插入

	//d1 << cout; // d1.operator<<(cout);

	cin >> d1 >> d2;
	cout << d1 << d2 << endl; // operator<<(cout, d1);
	cout << d1 - d2 << endl;
}


void TestDate5()
{
	Date d1(2022, 10, 10);
	d1.Print();

	const Date d2(2022, 10, 10);
	d2.Print();

	//d2 += 10;
	cout << d2 + 1000 << endl;

	cout << &d1 << endl;
	cout << &d2 << endl;
}



int main()
{
	//TestDate1();
	//TestDate2();

	//TestDate3();
	//TestDate4();

	TestDate5();

	return 0;
}

关于流插入与流提取的使用

关于流插入与流提取,这两家伙是被封装成类的,在使用时候需要注意 (比较复杂就不深入了)

当然还可以在类里面定义一个(日期)提取函数,这种方法Java语言中经常被使用 

以下代码是直接放在上面日期类代码一起的 

//为了重载流插入与流提取,需要加入这几句
using std::ostream;
using std::istream;
using std::cin;

在实现<<与>>俩个的重载需要明白下面这个注意事项

方法一:定义与声明分离 

需要注意的是,这里因为里面的成员对象是私有的,在外部是使用不了的,为此需要用到友元函数


//在日期类里面定义这两句声明
	friend ostream& operator<<(ostream& out, const Date& d);

	friend istream& operator>>(istream& in, Date& d);	


 

Date.h 

//全局函数不要写在.h文件里面,会有重命名的报错

//写在全局的原因是因为,this指针会占用第一个参数,导致这样写的函数重载用起来会很别扭
// d << out ,显然这样写是不符合我们使用流插入的习惯的

//流插入
ostream& operator<<(ostream& out, const Date& d);
//流提取
istream& operator>>(istream& in, Date& d);    //这里就不用加const,因为需要该d里面的值

Date.cpp

//流插入 <<
ostream& operator<<(ostream& out, const Date& d)
{
	out << d._year << "年" << d._month << "月" << d._day << endl;
	return out;
}

//流提取 >>
istream& operator>>(istream& in, Date& d)//这里就不用加const,因为需要该d里面的值
{
	in >> d._year >> d._month >> d._day;
	return in;
}

方法二:使用内联函数

该方法只需要在.h里面写就行了 (方法一里面的代码记得屏蔽,不然会报错)

Date.h

	friend inline ostream& operator<<(ostream& out, const Date& d);
	friend inline istream& operator>>(istream& in, Date& d);

//方法二:使用内联函数
//使用内联函数,也可以解决重命名的问题,因为内联函数也是不会进入符号表的
//内联与static的方法很像,不报错的原因都是不进入符号表,但是两者的意义不一样
//内联函数在使用的时候就会自动展开
//流插入
inline ostream& operator<<(ostream& out, const Date& d)
{
	out << d._year << "年" << d._month << "月" << d._day << endl;
	return out;
}
//流提取
inline istream& operator>>(istream& in, Date& d)//这里就不用加const,因为需要该d里面的值
{
	in >> d._year >> d._month >> d._day;
	return in;
}

const成员

概念 

        将const 修饰的 成员函数 称之为 const 成员函数 const 修饰类成员函数,实际修饰该成员函数 隐含的 this 指针 ,表明在该成员函数中 不能对类的任何成员进行修改。

关于上述日期类代码为什么需要在函数后面加入const 

  

总结:凡是内部不改变成员变量,即*this对象数据的,这些成员函数都应该加const

取地址及const取地址操作符重载

这两个默认成员函数一般不用重新定义 ,编译器默认会生成。

class Date
{ 
public :

 Date* operator&()
 {
     return this ;
 }

 const Date* operator&()const    //这个版本是给const类型变量调用的
 {
     return this ;
 }

private :
 int _year ; // 年
 int _month ; // 月
 int _day ; // 日
};

  

        这两个运算符一般不需要重载,使用编译器生成的默认取地址的重载即可,只有特殊情况,才需要重载,比如想让别人获取到指定的内容!

样例

	// 要求这个类的对象不让取地址
	Date* operator&()
	{
		return nullptr;
		//return this;
	}

	const Date* operator&() const
	{
		return nullptr;
		//return this;
	}

结束语

夫天未欲平治天下也;如欲平治天下,当今之世,舍我其谁也?

                                                                                                        ——《孟子》

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

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

相关文章

5G核心网技术基础自学系列 | 网络切片

书籍来源&#xff1a;《5G核心网 赋能数字化时代》 一边学习一边整理内容&#xff0c;并与大家分享&#xff0c;侵权即删&#xff0c;谢谢支持&#xff01; 附上汇总贴&#xff1a;5G核心网技术基础自学系列 | 汇总_COCOgsta的博客-CSDN博客 支持网络切片是设计5G架构的主要驱…

【牛客刷题--SQL篇】必会的常用函数之条件函数SQL26计算25岁以上和以下的用户数量(多种写法)

&#x1f496;个人主页&#xff1a;与自己作战 &#x1f4af;作者简介&#xff1a;CSDN博客专家、CSDN大数据领域优质创作者、CSDN内容合伙人、阿里云专家博主 &#x1f49e;牛客刷题系列篇&#xff1a;【SQL篇】】【Python篇】【Java篇】 &#x1f4cc;推荐刷题网站注册地址&a…

基于WEB的二维码生成系统设计与实现(Asp.net)

目 录 1 引言 6 2 二维码的生成原理 6 2.1基础知识 6 2.1.1定位图案 7 2.1.2功能性数据 8 2.1.3数据码和纠错码 8 2.2数据编码 8 2.3结束符和补齐符 9 2.3.1补齐码&#xff08;Padding Bytes&#xff09; 9 2.3.2纠错码 10 2.4最终编码 11 2.4.1穿插放置 11 2.4.2Remainder Bi…

JWT基础概念

1. 介绍 JWT &#xff08;JSON Web Token&#xff09; 是目前最流行的跨域认证解决方案&#xff0c;是一种基于 Token 的认证授权机制。 从 JWT 的全称可以看出&#xff0c;JWT 本身也是 Token&#xff0c;一种规范化之后的 JSON 结构的 Token。 JWT 自身包含了身份验证所需要…

【正点原子I.MX6U-MINI应用篇】6、嵌入式Linux在LCD屏幕上显示字符

一、原始方式&#xff1a; 取模显示字符 LCD显示屏是由width * height个像素点构成的&#xff0c;显示字符&#xff0c;一个非常容易想到的方法便是对字符取模&#xff0c;然后在LCD屏上打点显示字符&#xff1b;如果大家以前学习过单片机&#xff0c;想必接触过一些显示屏&am…

三次、五次多项式插值(附代码)

文章目录一、三次多项式插值二、五次多项式插值三、matlab代码三次、五次多项式插值在工程实践中很常见。求解多项式的系数最直接的方法是根据端点处的约束条件&#xff0c;列出线性方程组&#xff0c;再写成矩阵方程AXB&#xff0c;然后用通用的方法(如高斯消元法、LU分解等)解…

二叉树广度优先搜索、深度优先搜索(前序、中序、后序)遍历,动图详解-Java/Kotlin双版本代码

自古逢秋悲寂寥&#xff0c;我言秋日胜春朝 二叉树结构说明 本博客使用树节点结构&#xff0c;如下所示&#xff1a; Kotlin 版本 class TreeNode(var value: String, var leftNode: TreeNode? null, var rightNode: TreeNode? null)Java 版本 class TreeNode(){public…

经典排序之插入排序

目录 直接插入排序&#xff1a; 基本思路 图解过程 代码 复杂度分析 希尔排序 基本思想 图解过程 代码 复杂度分析 总结 参赛话题&#xff1a;学习笔记 直接插入排序&#xff1a; 基本思路 直接插入排序的工作方式像许多人排序一手扑克牌。开始时&#xff0c;我们的左手…

【Netty 从成神到升仙系列 大结局】全网一图流死磕解析 Netty 源码

&#x1f44f;作者简介&#xff1a;大家好&#xff0c;我是爱敲代码的小黄&#xff0c;独角兽企业的Java开发工程师&#xff0c;Java领域新星创作者。&#x1f4dd;个人公众号&#xff1a;爱敲代码的小黄&#x1f4d5;系列专栏&#xff1a;Java设计模式、数据结构和算法&#x…

第八篇 python 面向对象编程

11 面向对象编程 面向对象编程——Object Oriented Programming&#xff0c;简称OOP&#xff0c;是一种程序设计思想。OOP把对象作为程序的基本单元&#xff0c;一个对象包含了数据和操作数据的函数。 面向过程的程序设计把计算机程序视为一系列的命令集合&#xff0c;即一组…

Python攻防-APK批量化Pull与自动化反编译

文章目录前言Pull APK根据包名列表根据手机路径逆向APK自动化反编译findstr检索…总结前言 日常工作过程中&#xff0c;经常会遇到发现新的攻击模式的情况下&#xff0c;需要全量排查手机上所有 APP 的代码是否存在该类代码缺陷。对于复杂的攻击模式而言&#xff0c;往往需要动…

【MyBatis框架】动态SQL

MyBatis之动态SQL 目录MyBatis之动态SQL1. < if > 元素2. < where >3. < choose >,< when >,< otherwise >元素4. < trim >元素5. < set >元素6. < foreach >元素6.1 添加批量数据6.2 批量删除数据7. < SQL >元素8. 小结…

LVS负载均衡群集

企业群集应用 1. 群集的含义 1.1Cluster&#xff0c;群集&#xff0c;集群 2.1由多台主机构成&#xff0c;但对外&#xff0c;只表现为一个整体&#xff0c;只提供一个访问入口&#xff08;域名或ip地址&#xff09;&#xff0c; 相当于一台大型计算机 2.问题出现 互联网…

Sentinel的学习

1、Sentinel控制台的下载 下载地址&#xff1a;https://github.com/alibaba/Sentinel/releases/tag/1.8.3 2、Sentinel控制台的启动 java -jar sentinel-dashboard-1.8.3.jar3、访问 浏览器输入&#xff1a;localhost:8080 账号密码&#xff1a; sentinel/sentinel 4.sprin…

SARScape中用sentinel-1数据做SBAS-InSAR完整流程(1/2)

SARScape中用sentinel-1数据做SBAS-InSAR完整流程1 SABA-InSAR原理简述2 数据采集和预设2.1 SAR数据采集2.2 DEM数据下载与放置2.3 精密轨道数据下载与放置2.4 制作研究区范围矢量2.5 SARscape Preferences预设3 SAR数据预处理3.1 导入数据3.2 optional files设置3.3 参数设置4…

【Git】Git使用的三个场景总结 | 远程仓库到本地 | 本地获取git仓库 | 远程仓库与本地相连接

&#x1f4ad;&#x1f4ad; ✨&#xff1a; git使用的三个场景总结 | 远程仓库到本地 | 本地获取git仓库 | 远程仓库与本地相连接   &#x1f49f;&#xff1a;东非不开森的主页   &#x1f49c;&#xff1a;学习的过程就是不断接触错误&#xff0c;不断提升自己&#xff0c…

Linux 卸载zabbix图文教程

Linux 卸载zabbix图文教程前言1.停止zabbix服务2.卸载zabbix服务2.1查找zabbix所有被安装的rpm包2.2卸载zabbix服务2.3删除所有与zabbix相关的文件&#xff08;配置项等&#xff09;3.卸载数据库3.1查找mariadb所有被安装的rpm包&#xff0c;并删除3.2删除mysql相关配置文件4.卸…

Source Insight4.0中文注释乱码解决方案

一、Source Insight软件介绍 Source Insight是一个面向项目的编程编辑器、代码浏览器和分析器&#xff0c;可帮助您在工作和计划​​时分析代码&#xff0c;具有针对 C/C、C#、Java、Objective-C 等的内置动态分析&#xff0c;深受众多嵌入式软件开发者的喜爱。 二、中文乱码…

复旦-华盛顿大学EMBA 二十年20人丨徐欣:从外企转战民企的变身

复旦大学-华盛顿大学EMBA20周年校友系列访谈。      2008年堪称转折之年&#xff0c;中国举行北京奥运会向全世界展示“和而不同”的理念&#xff0c;入世7年让中国在贸易、金融领域与全球市场紧密相连&#xff0c;一大批最优秀的中国民营企业也加速踏上全球化之路。    …

Web APIs:PC 端网页特效--动画函数封装

动画原理 核心原理&#xff1a;通过定时器 setInterval() 不断移动盒子位置 实现步骤&#xff1a; 1. 获得盒子当前位置 2. 让盒子在当前位置加上1个移动距离 3. 利用定时器不断重复这个操作 4. 加一个结束定时器的条件 5. 注意此元素需要添加定位&#xff0c;才能使用e…