拷贝构造函数的用法

2024-04-13

拷贝构造函数的用法(共11篇)

篇1:拷贝构造函数的用法

jiu_acm

纸上得来终觉浅 绝知此事要躬行

拷贝构造函数的用法

1.拷贝构造函数是与类名相同,其形参是本类的对象的引用,

2.拷贝构造函数会在以下三种情况下被调用:

1).当用类的一个对象去初始化该类的另一个对象时。

2).如果函数的形参是类的对象,调用该函数,将对象作为函数实参传递给函数的形参时。

3).如果函数的返回值是类的对象,函数执行完成,将返回值返回时。

3.浅拷贝的失败例子:

1 #include

2 #include

3

4 using namespace std;

5

6

7 class str

8 {

9 private:

10char *s;

11int len;

12 public:

13str()

14{

15len=0;

16s=NULL;

17}

18str(const char *p)

19{

20len=strlen(p);

21s=new char[len+1];

22strcpy(s,p);

23}

24~str()

25{

26if(s!=NULL)

27{

28delete []s;

29s=NULL;

30}

31}

32 };

33

34 int main()

35 {

36str s1(”I love you!");

37str s2=s1;//这里会发生错误,

38return 0;

39 }

之所以发生错误是因为两个对象在析构时都要delete那块堆里的内存,但是程序里是浅拷贝,也就是说,s2只拷贝了s1的堆内存的地址,s2的s指针指向s1申请的堆内存,两次delete同一块内存,明显不合法。故而需要增加自定义拷贝构造函数,即深拷贝。见于下例:

1 str(str &r)

2 {

3len=r.len;

4if(len!=0)

5{

6s=new char[len+1];

7strcpy(s,r.s);

8}

9 }

4.注意:

1).在自定义拷贝构造函数后,缺省拷贝构造函数和构造函数失效,构造函数需要自定义。

2).在自定义构造函数后,缺省构造函数失效,但缺省拷贝构造函数仍有效。

篇2:拷贝构造函数的用法

在讲课过程中,我发现大部分学生对拷贝构造函数的理解不够深入,不明白自定义拷贝构造函数的必要性。因此,我将这部分内容,进行了总结。

拷贝构造函数是一种特殊的构造函数,其形参为本类的对象引用。功能:使用一个已经存在的对象始初化同类的一个新对象。这样得到对象和原来的对象具有完全相同的数据成员,即相同的属性。

拷贝构造函数的函数原型:

A(const A& other){ … … }

拷贝构造函数的应用场合:

当用类的一个对象去初始化该类的另一个对象时;若函数的形参为类对象,调用函数时,实参赋值给形参;当函数的返回值是类对象时。比如:

A a1(10);

A a2 = a1;

A a3(a1);// 构造函数 // 拷贝构造函数 // 拷贝构造函数

默认拷贝构造函数:成员变量之间的“值”拷贝

编写拷贝构造函数的必要性

class A

{

public:

A(const char* data)

{

name = new char[strlen(data)+ 1];

strcpy(name, data);

}

A(const A& other)

{

name = new char[strlen(other.name)+ 1];

strcpy(name, other.name);

}

private:

char* name;

};

考察:char* data = “abcd”;A a1(data);A a2 = a1;

如果未定义拷贝构造函数,会有何种后果?

篇3:拷贝构造函数的用法

拷贝构造函数和赋值运算符函数是C++的两个重要概念, 也是类特征的重要体现, 二者在定义和使用中有相似点, 也有一定的区别。掌握好这二者对于深入理解类和C++程序大有裨益。但是很多时候, 对于什么时候应该定义这两个函数, 什么时候使用他们, 以及在使用中他们有什么区别等这些问题, 书中很少对二者进行系统的归纳和对比。本文正是基于这些问题, 对二者进行了详尽的分析比较。

2、浅拷贝和深拷贝问题

我们都知道, 对于系统自定义类型, 如整形变量的赋值操作是由"="运算符完成的。但是面向对象中的类是一种自定义类型, 当用一个对象去初始化另一个对象或用一个对象给另一个对象赋值的时候, C++系统需要采取特殊的方式来完成这种操作, 这就是拷贝构造函数和赋值运算符函数。但是我们又发现有时侯程序中并没有所说的拷贝构造函数和赋值运算符函数, 这是因为系统已经为我们定义了默认的拷贝构造函数和赋值运算符函数, 他们的作用就是把初始值对象的每个数据成员的值复制到新建立的或已存在的另一个对象中。那为什么还要自定义他们呢?这是因为当类的数据成员中有指针类型时, 默认的拷贝构造函数和赋值运算符函数实现的只能是浅拷贝, 浅拷贝会带来数据安全方面的隐患。下面从例1分析浅拷贝带来的问题。

该程序有运行错误提示并且运行的结果如下所示:

为什么会出现这样的结果呢, 首先以图1为例, 看一下默认的拷贝构造函数实现的功能。从图1中可以看出, 这里只是将对象one中字符指针的首地址简单赋值给了对象two的指针成员, 对象two根本没有构造自己的字符数组空间, 结果造成对象one和two共同使用同一块内存空间存放字符数组元素。所以当对象two生存期结束, 调用析构函数时, 对象one中指针成员对应的内存空间也被释放掉了, 这种情况也被称为指针悬挂。所以对象one在访问这块内存时, 就会出现运行错误。

我们再以图2为例, 看一下默认的赋值运算符函数实现的功能。从图2可以看出, 这里同样只是将对象four中字符指针的首地址简单赋值给了对象three的指针成员, 造成对象four和three共同使用同一块内存空间存放字符数组, 所以也出现了上述的运行结果。上述两种赋值方式都是仅仅将对象的数据成员进行了对应的拷贝。这种拷贝方式称为浅拷贝。

为了避免上述结果, 下面对例1中的CPerson类进行修改。例2加进自定义的拷贝构造函数和赋值运算符重载函数, 从例子注释中可以看到, 二者都有内存空间开辟和字符串拷贝的语句, 亦即在进行赋值之前, 为指针类型的数据成员另辟了一个独立的内存空间, 实现真正内容上的拷贝。这种拷贝称为深拷贝。深拷贝方式有效的解决了上述的指针悬挂问题。

3、二者使用中的区别

定义好拷贝构造函数和赋值运算符函数后, 虽然二者的功能比较相似, 但是二者定义的区别决定了他们在使用中的区别。拷贝构造函数是在创建新对象时由已存在对象初始化新对象时调用的;赋值运算符函数是在两个对象都已创建好的情况下, 由一个对象给另一个对象赋值时调用的。通过下例可以看出他们的主要区别。

并且由于在多种情况下均会涉及到对象的新建, 所以拷贝构造函数在以下三种情况下都会被调用。

(1) 当用类的一个对象去初始化该类的另一个对象时。如上例。

(2) 如果函数的形参是类的对象, 调用函数时, 进行形参和实参结合时。

(3) 如果函数的返回值是类的对象, 函数执行完成返回调用者时。

4、定义形式上的比较

拷贝构造函数可以有多个参数, 但是第一个参数必须为对象的引用。重载赋值运算符函数只有一个参数, 该参数也必须是对象的引用。参数为引用可以省去开辟对象空间的麻烦。与拷贝构造函数不同的是, 其返回值类型也必须是对象的引用, 为什么这里要定义为引用呢?首先, 引用的实质是对象的地址, 所以通过引用可以改变对象的值。所以返回值为引用的函数可以作为表达式的左值使用。其次, 有些运算符表达式是不能作为左值的, 比如a+b=5;语法中c++这样的表达是不合法的, 而赋值运算符表达式可以作为一个表达式的左值使用, 比如int a=b=3;其中a=b的值作为左值又被赋了值, 即左值是可以改变的。正是这样, 就要求赋值运算符函数必须能够作为左值使用, 如果函数的返回值是一个对象的值, 它就被认为是一个常量, 当然不能成为左值。所以重载赋值运算符函数的返回值必须是引用, 否则会出错。

5、结束语

在面向对象程序设计中, 拷贝构造函数与赋值运算符函数是两个既相似又重要的成员函数, 在使用过程中非常容易混淆。本文从他们的最初定义到使用过程都进行了详细的分析总结, 指出了二者的相似点和使用中的区别。只有熟练的使用二者, 才能更好的理解类的机制, 掌握c++的编程思想, 提高编程的灵活性和正确性。

参考文献

[1]陈维兴, 林小茶.《c++面向对象程序设计教程》 (第二版) .清华大学出版社, 186-189

[2]郑莉, 董渊.《c++语言程序设计》 (第二版) .清华大学出版社.

[3]郑阿奇, 丁有和.《Visual C++应用教程》.人民邮电出版社.

篇4:构造恰当的函数

例 已知函数f(x)=x+■+5-m,m∈R. 试讨论关于x的方程f(x)=0的正实数解的个数.

解法一:方程的解即函数f(x)的零点,要讨论f(x)=0的正实数解的个数,我们可以研究f(x)在(0,+∞)上的图象.

f′(x)=1-■=■.

当x>0,m≤4时,∵ (x+2)2>4, ∴ f′(x)>0, f(x)在(0,+∞)上单调递增.又f(0)=5-■>0, ∴ f(x)的大致图象如图1所示, 此时 f(x)没有正的零点.

当x>0,m>4时, f′(x)=■,当0■-2时,f′(x)>0, f(x)单调递增. f(x)的大致图象如图2所示.

当f(x)min=f(■-2)=2■+3-m=0,即m=9时,f(x)有1个正的零点;

当f(■-2)>0,即4

当f(■-2)<0且f(0)=5-■>0,即9

当f(■-2)<0且f(0)≤0,即m≥10时, f(x)有1个正的零点.

综上所述,当m<9时,方程f(x)=0没有正实数解;当m=9或m≥10时,方程f(x)=0有1个正实数解;当9

评析:用函数的零点来解决方程的解的问题,是解答例题的关键. 解法一直接利用了条件中的现成函数来作图,但这个函数含有参数,所以要进行分类讨论,解答过程不免有些繁冗.

解法二:采用变量分离法,由方程x+■+5-m=0可得m=■,于是,方程的正实数解的个数就是函数y=m和函数g(x)=■ (x>0)的图象交点的个数.

g′(x)=■. 当x>1时,g′(x)>0,g(x)单调递增;当0

评析:解法二通过变量分离法,将方程解的问题转化为关于x的新函数g(x)与y=m的交点问题,其好处是g(x)不再含有参数m,无需对m的取值范围进行分类讨论,优化了解答过程.

解法三:对方程x+■+5-m=0去分母整理得:m(x+1)=x2+7x+10 (①),所以方程的正实数解的个数就是直线y=m(x+1)和抛物线g(x)=x2+7x+10在(0,+∞)上的交点个数.

如图4所示,直线y=m(x+1)过定点(-1,0),当直线与抛物线相切于y轴右侧,即直线与抛物线在x∈(0,+∞)上只有一个交点时,通过①式的判别式Δ=(7-m)2-4(10-m)=0可解得m=9. 当直线过(0,10)时,直线y=m(x+1)与抛物线也只有一个交点,解得m=10. 根据直线斜率的变化可知,当m<9时,方程f(x)=0没有正实数解;当m=9或m≥10时,方程f(x)=0有1个正实数解;当9<m<10时,方程f(x)=0有2个正实数解.

评析:在解法三中,方程的变形是有“预谋”的,目的是构造更简单的函数. 第一步去分母是为了去掉分式函数,第二步整理方程得到①式是为了在方程的等号两边构造我们熟悉的一次函数和二次函数,这样两个函数的图象就可不经过求导直接作出,解答过程更加简洁明了.

小结:从以上分析可以看出,题干给出的函数不一定是我们用来作图分析的最佳选择.有效的策略是:首先利用方程和不等式的性质对数式进行变形化简,简化运算过程;其次,方程和不等式问题的本质就是对等式或不等式两边的函数进行比较,所以要有目的地对等式或不等式进行转化,构造恰当的函数,使图形操作更简便可行.

【练一练】

已知关于x的不等式x2+2x-t+1>x-t恒成立,求t的取值范围.

【参考答案】

篇5:拷贝构造函数的用法

在C++中,构造函数,拷贝构造函数,析构函数和赋值函数(赋值运算符重载)是最基本不过的需要掌握的知识。但是如果我问你“拷贝构造函数的参数为什么必须使用引用类型?”这个问题,你会怎么回答? 或许你会回答为了减少一次内存拷贝? 很惭愧的是,我的第一感觉也是这么回答。不过还好,我思索一下以后,发现这个答案是不对的。

原因:

如果拷贝构造函数中的参数不是一个引用,即形如CClass(const CClass c_class),那么就相当于采用了传值的方式(pass-by-value),而传值的方式会调用该类的拷贝构造函数,从而造成无穷递归地调用拷贝构造函数。因此拷贝构造函数的参数必须是一个引用。

需要澄清的是,传指针其实也是传值,如果上面的拷贝构造函数写成CClass(const CClass* c_class),也是不行的。事实上,只有传引用不是传值外,其他所有的传递方式都是传值。

先从一个小例子开始:(自己测试一下自己看看这个程序的输出是什么?)

[cpp] view plain copy #include

using namespace std;

class CExample

{

private:

int m_nTest;

public:

CExample(int x): m_nTest(x)

//带参数构造函数

{

cout << “constructor with argument”<

}

// 拷贝构造函数,参数中的const不是严格必须的,但引用符号是必须的 CExample(const CExample & ex)

//拷贝构造函数

{

m_nTest = ex.m_nTest;

cout << “copy constructor”<

}

CExample& operator =(const CExample &ex)

//赋值函数(赋值运算符重载)

{

cout << “assignment operator”<

m_nTest = ex.m_nTest;

return *this;

}

void myTestFunc(CExample ex)

{

}

};

int main(void)

{

CExample aaa(2);

CExample bbb(3);

bbb = aaa;

CExample ccc = aaa;

bbb.myTestFunc(aaa);

return 0;

}

这个例子的输出结果是: [cpp] view plain copy constructor with argument

// CExample aaa(2);

constructor with argument

// CExample bbb(3);

assignment operator

// bbb = aaa;

copy constructor

// CExample ccc = aaa;

copy constructor

// bbb.myTestFunc(aaa);

如果你能一眼看出就是这个结果的话,恭喜你,可以站起来扭扭屁股,不用再往下看了。

如果你的结果和输出结果有误差,那拜托你谦虚的看完。

第一个输出: constructor with argument

// CExample aaa(2);

如果你不理解的话,找个人把你拖出去痛打一顿,然后嘴里还喊着“我是二师兄,我是二师兄.......”

第二个输出:constructor with argument

// CExample bbb(3);

分析同第一个

第三个输出: assignment operator

// bbb = aaa;

第四个输出: copy constructor

// CExample ccc = aaa;

这两个得放到一块说。肯定会有人问为什么两个不一致。原因是,bbb对象已经实例化了,不需要构造,此时只是将aaa赋值给bbb,只会调用赋值函数,就这么简单,还不懂的话,撞墙去!但是ccc还没有实例化,因此调用的是拷贝构造函数,构造出ccc,而不是赋值函数,还不懂的话,我撞墙去!

第五个输出: copy constructor

// bbb.myTestFunc(aaa);

实际上是aaa作为参数传递给bbb.myTestFunc(CExample ex),即CExample ex = aaa;和第四个一致的,所以还是拷贝构造函数,而不是赋值函数,如果仍然不懂,我的头刚才已经流血了,不要再让我撞了,你就自己使劲的再装一次吧。

通过这个例子,我们来分析一下为什么拷贝构造函数的参数只能使用引用类型。

看第四个输出: copy constructor

// CExample ccc = aaa;

构造ccc,实质上是ccc.CExample(aaa);我们假如拷贝构造函数参数不是引用类型的话,那么将使得 ccc.CExample(aaa)变成aaa传值给ccc.CExample(CExample ex),即CExample ex = aaa,因为 ex 没有被初始化,所以 CExample ex = aaa 继续调用拷贝构造函数,接下来的是构造ex,也就是 ex.CExample(aaa),必然又会有aaa传给CExample(CExample ex), 即 CExample ex = aaa;那么又会触发拷贝构造函数,就这下永远的递归下去。

所以绕了那么大的弯子,就是想说明拷贝构造函数的参数使用引用类型不是为了减少一次内存拷贝,而是避免拷贝构造函数无限制的递归下去。

附带说明,在下面几种情况下会调用拷贝构造函数:

a、显式或隐式地用同类型的一个对象来初始化另外一个对象。如上例中,用对象c初始化d; b、作为实参(argument)传递给一个函数。如CClass(const CClass c_class)中,就会调用CClass的拷贝构造函数;

c、在函数体内返回一个对象时,也会调用返回值类型的拷贝构造函数;

d、初始化序列容器中的元素时。比如 vector svec(5),string的缺省构造函数和拷贝构造函数都会被调用;

e、用列表的方式初始化数组元素时。string a[] = {string(“hello”), string(“world”)};会调用string的拷贝构造函数。

如果在没有显式声明构造函数的情况下,编译器都会为一个类合成一个缺省的构造函数。如果在一个类中声明了一个构造函数,那么就会阻止编译器为该类合成缺省的构造函数。和构造函数不同的是,即便定义了其他构造函数(但没有定义拷贝构造函数),编译器总是会为我们合成一个拷贝构造函数。

另外函数的返回值是不是引用也有很大的区别,返回的不是引用的时候,只是一个简单的对象,此时需要调用拷贝构造函数,否则,如果是引用的话就不需要调用拷贝构造函数。[cpp] view plain copy #include

using namespace std;

class A

{

private:

int m_nTest;

public:

A()

{

}

A(const A& other)

//构造函数重载

{

m_nTest = other.m_nTest;

cout << “copy constructor”<

}

A & operator =(const A& other)

{

if(this!= &other)

{

m_nTest = other.m_nTest;

cout<<“Copy Assign”<

}

return *this;

}

};

A fun(A &x)

{

return x;

//返回的不是引用的时候,需要调用拷贝构造函数

}

int main(void)

{

A test;

fun(test);

system(“pause”);

return 0;

}

分享一道笔试题目,编译运行下图中的C++代码,结果是什么?(A)编译错误;(B)编译成功,运行时程序崩溃;(C)编译运行正常,输出10。请选择正确答案并分析原因。

[cpp] view plain copy class A

{

private:

int value;

public:

A(int n)

{

value = n;

}

A(A other)

{

value = other.value;

}

void Print()

{

cout<

}

};

int main(void)

{

A a = 10;

A b = a;

b.Print();

return 0;

}

篇6:拷贝构造函数的用法

#includeusing namespace std;//c++中六种默认的构造函数class Test{public: Test(int d = 0):m_data(d)//1构造函数(带默认值0),以参数列表的形式初始化 { cout<<“Creat Test Obj :”<

情况一:

“ int=”int“ main=”main{“ pre=”pre“ return=”return“ t=”t){“ t1=”fun(t);“ t10=”t(10);“ test=”Test“ tmpint=”tmp;}int“ tmpvalue=”tmp(value);“ value=”t.GetData();“>

情况二:

//2Test fun(Test t){ int value = t.GetData(); return Test(value);}int main(){ Test t(10); Test t1; t1 = fun(t); return 0;}

情况三:

//3Test fun(Test &t){ int value = t.GetData(); Test tmp(value); return tmp;}int main(){ Test t(10); Test t1; t1 = fun(t); return 0;}

情况四:

//4Test fun(Test &t){ int value = t.GetData(); return Test(value);}void main(){ Test t(10); Test t1; t1 = fun(t);}

情况五:

//5Test& fun(Test &t){ int value = t.GetData(); Test tmp(value); return tmp;}void main(){ Test t(10); Test t1; t1 = fun(t);}

情况六:

//6Test& fun(Test &t){ int value = t.GetData(); return Test(value);}void main(){ Test t(10); Test t1; t1 = fun(t);}

情况七:

//7Test fun(Test &t){ int value = t.GetData(); return Test(value);}void main(){ Test t(10); Test t1 = fun(t);}

情况八:

//8Test fun(Test &t){ int value = t.GetData(); Test tmp(value); return tmp;}void main(){ Test t(10); Test t1 = fun(t);}

情况九:

Test& fun(Test &t){ int value = t.GetData(); Test tmp(value); return tmp;}void main(){ Test t(10); Test t1; t1 = fun(t);}

综上所述:

一:调用拷贝构造函数的情况:

1)直接用对象初始化对象

2)形参数对象时,用实参对象初始化

3)函数的返回值类型是类时(非引用)是,拷贝构造无名的临时空间作为函数返回值

二:注意:

当函数的返回值是该函数中的一个临时对象时,函数类型不可以定义为Test &即引用,否则会发生,用一个已经析构的临时对象初始化另外一个对象,会发生错误;

三:提高效率的方式:

1)形参用引用,不再调用拷贝构造函数

2)返回一个无名的临时对象a,系统不再创建另外的一个临时对象而直接将a作为返回值,(函数返回类型不是引用)

3)返回无名的临时对象,且用它初始化另外一个对象,如情况七,直接将无名的对象作为另外的一个对象

4)上述三种情况结合;

篇7:拷贝构造函数的用法

方法重载

可以使同一功能适用于各种类型的数据,它是声明两个以上的同名方法,实现对不同数据类型进行相同的处理 方法重载的要求

1、重载的方法名称必须相同

2、重载的方法,其形参个数或类型必须不同

如我们定义了swap(ref int a,ref intb)该函数用来实现两个整形变量值的交换,但不会处理浮点型数据,我们在定义一个swap(ref flot a,ref flot b),这样swap这个方法可以实现整形变量值的交换,也可以实现浮点型数据交换了(系统会根据数据的类型自己决定调用合适的方法)构造函数

主要作用是在创建对象(声明对象)时初始化对象。一个类定义必须至少有一个构造函数,如果定义类时,没有声明构造函数,系统会提供一个默认的构造函数。举个例子或许可以更好的理解它: 结果是:

若想在创建对象时,将对象数据成员设定为指定的值,则要专门声明构造函数。声明构造函数的要求:

1、构造函数不允许有返回类型

2、构造函数名称必须与类同名。

通常构造函数是为了在创建对象时对数据成员初始化,所以构造函数需要使用形参。public Student(string ID,int Age){

id=ID;

age=Age;} 由于上述构造函数带了参数,系统不会提供默认构造函数,所以在创建对象时,必须按照声明的构造函数的参数要求给出实际参数。

Student s1= new Student(“90090”,22);New关键字后面实际是对构造函数的调用。

如果声明构造函数时使用的参数名称和类数据成员名称相同,那么构造函数中使用的类数据成员名称要有this引导 Public student(string id,int age){

This.id=id;

This.age=age;} 关键字this指的是创建的对象,是声明对象时,由系统自动传递给构造函数的对象的引用形参。重载构造函数

构造函数和方法一样都可以重载。重载构造函数的主要目的是为了给创建对象提供更大的灵活性,以满足创建对象时的不同需要。

如上面的例子,如果只想改变age则重载构造函数Student只需要有一个参数age就可以了。虚方法

声明与基类同名的派生类方法 Public new 方法名称(参数列表){} 声明虚方法

基类中声明格式

Publicvirtual方法名称(参数列表){}

派生类中声明格式

Publicoverride方法名称(参数列表){}

调用基类方法

在派生类中声明一基类同名的方法,也叫方法重载。在派生类重载基类方法后,如果像调用基类的同名方法,使用base关键字。

声明抽象类和抽象方法 Public abstractclasse 类名称 {public abstract 返回类型方法名称(参数列表);} 重载抽象方法

篇8:拷贝构造函数的用法

【例1】 若定义在R上的函数f (x) 满足:对任意x1, x2∈R有f (x1-x2) =f (x1) +f (-x2) -2, 则下列结论正确的是 ( ) .

A.f (x) 的图像关于原点对称

B.f (x) 的图像关于点 (0, -2) 对称

C.f (x) 的图像关于点 (0, 2) 对称

D.f (x) 的图像关于y轴对称

解法1:∵f (x1-x2) =f (x1) +f (-x2) -2,

f (x1+x2) =f (x1) +f (x2) -2,

f (x1+x2) -2=f (x1) -2+f (x2) -2.

F (x) =f (x) -2, 则F (x1+x2) =F (x1) +F (x2) , 这里x1, x2∈R.

在上式中令x1=x2=0, 则F (0) =2F (0) , ∴F (0) =0,

再令x1=x, x2=-x, 则F (0) =F (x) +F (-x) ,

F (-x) =-F (x) .

这里x∈R, 所以F (x) 是奇函数, 即f (x) -2是奇函数, 故函数f (x) -2的图像关于原点对称, 将f (x) -2的图像向上平移2个单位得f (x) 的图像, 故f (x) 的图像关于点 (0, 2) 对称.

解法2:我们找一个已学过的函数模型让它满足题目条件 (例如:一次函数, 二次函数, 指数函数, 对数函数) , 而条件可看作线性关系, 设f (x) =kx+b, 则由f (x1-x2) =f (x1) +f (-x2) -2可得b=2, ∴f (x) =kx+2, 则f (x) 的图像关于点 (0, 2) 对称.

评析:很明显, 解法1很难入手, 解法2则找到了原型函数, 变得非常容易.

【例2】 设函数y=f (x) 满足f (x+1) =f (x) +1, 则函数y=f (x) 与y=x图像交点的个数可能是 ( ) .

A.无穷多个

B.0个或者有限个

C.有限个

D.0个或者无穷多个

解法1:由f (x+1) =f (x) +1可知f (x+1) -f (x) =1, 即自变量增加1则函数值也增加1, 若函数f (x) 的图像与直线y=x有交点, 则必有无数个;否则, 无交点.

解法2:很显然, 条件满足线性关系, 设f (x) =kx+b, 由f (x+1) =f (x) +1可知k=1, 则当b=0时, y=f (x) =xy=x图像重合, 则有无穷多个交点;当b≠0时, y=f (x) =xy=x图像平行, 则有0个交点.

评析:显然解法2更直观、清晰.

【例3】 已知定义在R上的奇函数f (x) 的图像关于直线x=1对称, f (-1) =1, f (1) +f (2) +f (3) +…+f (2009) 的值为 ( ) .

A.-1 B.0

C.1 D.2

解法1:由f (x) 的图像关于直线x=1对称, 得f (x) =f (2-x) , 由f (x) 为奇函数, 得f (2-x) =-f (x-2) , 因此f (x) +f (x-2) =0.

那么f (2) +f (4) +f (6) +f (8) +…+f (2008) =0,

f (3) +f (5) +f (7) +f (9) +…+f (2009) =0,

于是f (1) +f (2) +f (3) +…+f (2009) =f (1) =-f (-1) =-1.

解法2:考虑到周期性, 可联想正弦函数和余弦函数, 根据条件可以构造

y=f (x) =-sinπ2x.f (1) +f (2) +f (3) +f (4) =0

所以f (1) +f (2) +f (3) +…+f (2009) =f (2009) =f (4×502+1) =f (1) =-f (-1) =1.

篇9:辅助函数的构造和应用

关键词:辅助函数 微分中值定理

中图分类号:G633.6 文献标识码:A 文章编号:1672-8882(2012)02-109-01

1、在微分中值定理证明中的应用

微分中值定理在高等数学中起着重要的作用,更是导数应用的基础。为了探讨辅助函数在证明这些定理中的应用,现将三个中值定理引述如下:

罗尔定理

如果函数f(x)满足:

(1)在闭区间[a, b]上连续;

(2)在开区间(a, b)内可导;

(3)fa=f(b),

那么在(a, b)内至少存在一点ξ, 使得f'ξ=0.

拉格朗日中值定理

如果函数f(x)满足:

(1)在闭区间[a, b]上连续;

(2)在开区间(a, b)内可导,

那么在(a, b)内至少存在一点ξ, 使得等式fb-fa=f'ξ(b-a)成立.

柯西中值定理

如果函数f(x)和g(x)满足:

(1)在闭区间[a, b]上连续;

(2)在开区间(a, b)内可导;

(3)对任一x∈a, b, g'(x)≠0,

那么在(a, b)内至少存在一点ξ, 使得等式

fb-f(a)gb-g(a)=f'(ξ)g'(ξ)

成立.

很多教材在证明拉格朗日和柯西中值定理时都是通过几何的方法来构造辅助函数,这种方法虽然比较直观,但是不容易想到。仔细比较上述三个定理的条件和结论,我们会发现它们存在及其相似的地方,联想到能不能使用类似的方法来解决呢?

2、在证明方程根的存在性中的应用

证明方程根的存在性的问题一般分为两类,一类是利用闭区间上连续函数的零点定理或介值定理去证明,另一类是利用微分中值定理去证明。

例1 设f(x)在[0, 2a]上连续, 且f0=f(2a), 证明: 在[0, a]上至少存在一点ξ,使fξ=f(ξ+a).

分析: 欲证本题,只需证明fξ-fξ+a=0即可。如果将等式看作某个函数在ξ处的函数值等于零,则ξ就是该函数的零点。本题就转化为了证明该函数在[0, a]上至少存在一个零点。因此可设该函数为:

φx=fx-f(x+a),

利用零点定理得到所求结论。

证明: 设φx=fx-f(x+a), 显然φ(x)在[0, a]上连续。且

φ0=f0-f(a)

φa=fa-f2a=fa-f0=-[f0-f(a)]

若f0=f(a), 则令ξ=0或ξ=a即为所求。若f0≠f(a), 则φ0?φ(a)<0,根据零点定理在(0, a)内至少存在一点ξ, 使φξ=0, 即fξ=f(ξ+a). 综上,在[0, a]上至少存在一点ξ,使fξ=f(ξ+a).

例2 设实数a1,a2,…,an满足

a1-a23+…+(-1)n-1an2n-1=0,

证明方程

a1cosx+a2cos3x+…+ancos2n-1x=0

在0, π2内至少有一个实根。

分析: 若设

fx=a1cosx+a2cos3x+…+ancos2n-1x,

则fπ2=0, f0=a1+a2+…+an, 根据题目条件不能得到f0=0, 因此无法使用零点定理。注意到函数

g(x)=a1cosx+a2cos3x+…+ancos2n-1x

的一个原函数是

Gx=a1sinx+a23sin3x+…+an2n-1sin2n-1x.

再与题目条件对比,容易想到构造辅助函数G(x).

证明: 令

Gx=a1sinx+a23sin3x+?+an2n-1sin2n-1x.

则G(x)在[0, π2]上连续,在(0, π2)内可导,且

G0=0=a1-a23+…+(-1)n-1an2n-1=G(π2)

根据罗尔定理,必有ξ∈(0, π2), 使G'ξ=0, 即

a1cosξ+a2cos3ξ+…+ancos2n-1ξ=0,

说明方程

a1cosx+a2cos3x+…+ancos2n-1x=0

在(0, π2)内至少有一个实根。

3、在证明不等式中的应用

如果不等式为函数不等式,则通过移项(也可以先做恒等变换再移项),使不等式一端为0,另一端即可设为辅助函数。如果不等式为文字不等式,则先观察哪个文字在不等式中出现的次数较多,然后把它改为x, 在移项是不等式一端为0,另一端就是可设为辅助函数。

例3当0<α<β<π 时,证明: βsinβ+2cosβ+πβ>αsinα+2cosα+πα.

分析: 考察所证不等式,不等号的两边可分别看函数

fx=xsinx+2cosx+πx

在β和α两点的函数值,根据题目条件,只要能够证明f(x)在(0, π)上是增函数即可。

证明: 设函数

fx=xsinx+2cosx+πx

则f'x=xcosx-sinx+π, 由于f''x=-xsinx<0, 当x∈(0, π). 且f'π=0, 所以当x∈(0, π)时,f'x>f'π=0. 从而,f(x)在(0, π)上是增函数,又因为0<α<β<π,所以fβ>f(α), 即

βsinβ+2cosβ+πβ>αsinα+2cosα+πα.

综上所述,构造辅助函数可以方便地解决很多问题,而且通过这种训练还可以培养学生的发散思维能力。

参考文献:

[1]划玉莲. 数学分析.[M]高等教育出版社, 1991

[2]李君士. 两个微分中值定理证明中辅助函数的多种作法[J]. 数学的实践与认识, 2004, 34(10): 165一169

篇10:数学解题中的函数构造策略

关键词:函数,方程,不等式

一、引 言

构造性解题方法是一种古老而又崭新的科学方法, 历史上许多著名的数学家如欧几里得、高斯、拉格朗日等人, 都曾用这一方法成功地解决过数学中的难题.本文主要从“构造函数解决一些方程和不等式问题”来阐述构造函数法在数学解题中的重要作用, 同时也给出一些关于构造函数解题的看法.

二、构造函数法在数学解题中的重要作用

1.构造函数在解决一些方程问题中的优越性

函数的思想, 就是利用变化的观点, 把研究的数量关系用函数的形式表示出来, 然后利用函数性质进行研究, 最终使问题获解.一旦给出具体形式的方程, 就可以转化为求解相应函数取值为零时的情形, 使问题顺利获解的同时, 优化了解题.

例1 已知多项式函数P (x) =x5+ax4+bx3+cx2+dx+e满足关系式P (1) =1997, P (2) =3994, P (3) =5991, P (4) =7998, 求表达式P (10) +P (-5) 的值.

分析 此题若按常规求解, 逐一将x=1, 2, 3, 4代入, 求解系数a, b, c, d, e, 势必带来繁琐的计算, 当然这样解题也不是命题者的初衷.其实解题的关键是:

(1) 归纳得到P (x) =1997x (x=1, 2, 3, 4, x∈Z) .

(2) 构造函数Q (x) =P (x) -1997x, (x∈Z) , 将方程转化为函数问题.

(3) 利用因式定理分解Q (x) .

事实上, Q (x) = (x-1) (x-2) (x-3) (x-4) (x-r) , r∈Z, 代入解得结果为75315.

评注 函数Q (x) 的出现, 使得解题简捷了许多.对于此类给出方程的基本形式及其若干取值的题型, 经常考虑构造函数, 结合因式定理来求解.

通过对上述例子的分析与评注, 我们发现, 对于一些特殊的函数方程问题, 直接求解未必能使问题顺利获解, 或者解题效率不高.此时我们必须认真分析条件与结论, 探究其内在的联系, 构造出适当的函数, 转化解题思路, 最终达到较为理想的解题效果.

2.构造函数在解决一些不等式问题中的优越性

不等式问题是数学解题的一个重要对象, 因此寻求实用有效的解题策略就非常有必要.由于不等式也蕴涵在函数观点之下, 所以利用函数思想来解决不等式问题也成为许多解题爱好者竞相尝试的一种方法, 而且收到了不错的效果.

例2 设A, B, C∈R, 多元函数f (x, y, z) =A (x-y) · (x-z) +B (y-x) (y-z) +C (z-x) (z-y) .求对于任意的x, y, z∈R, 不等式f (x, y, z) ≥0恒成立的充要条件.

分析 显然, 若x=y=z, f (x, y, z) =0符合题意, 故可设yz, 将函数f (x, y, z) =A (x-y) (x-z) +B (y-x) (y-z) +C (z-x) (z-y) 适当变形, 得到f (x, y, z) =A (x-y) 2- (B-A-C) (x-y) (y-z) +C (y-z) 2.

于是f (x, y, z) =A (x-y) 2- (B-A-C) (x-y) (y-z) +C (y-z) 2≥0恒成立等价于二次函数f (t) =At2- (B-A-C) t+C≥0恒成立, 其中t= (y-z) -1 (x-y) .利用二次函数的性质即可求得充要条件.

评注 在处理许多有关“恒成立”的不等式问题时, 我们经常借助构造二次函数f (x) =ax2+bx+c, 利用它的一些性质:

a>0时, Δ≤ (<) 0等价于f (x) ≥ (>) 0恒成立;

a<0时, Δ≤ (<) 0等价于f (x) ≤ (<) 0恒成立,

把问题转化, 以便从更为便捷的途径将问题解决.这一方法在求解变元的取值范围、证明不等式问题上也很奏效.利用此法证明柯西不等式, 会让我们看到其独到性和优越性.

从以上例子我们不难发现:许多不等式问题, 如果不经过适当的变形, 在求解时往往会出现不少障碍, 有碍我们解题;有时即便已经做了合理的转化, 如果不借助函数手段, 也很难简捷有效地解决问题.为此, 熟练掌握构造函数, 利用函数思想巧解不等式问题这一项解题技巧, 对于我们今后的教学工作, 尤其是解题教学大有裨益.

三、构造函数求解方程和不等式问题中的误区

作为一种解题策略, 构造函数解题具有简捷实用的特点, 因而容易使人产生误解, 片面夸大了其解题的优越性和实用性, 而忽视了策略自身的本质, 即策略只有得到有效使用时才能体现其价值.

1.审题不清, 强行构造函数, 造成运算繁琐

其实对于含参数及变量的方程和不等式问题, 考虑运用构造函数解题当然是可取的, 但未必是最佳的.由于实现解题的最优化才是解题教学的本质, 而数学问题的解决具有多种方法和途径, 因此选择合适的解题策略非常重要.

2.理解不透, 构造函数不当, 使解题陷入瘫痪

事实上, 对于一类特殊的数学问题, 构造函数是非常理想的解题策略, 而且有时候无法用其他策略来替代.在正确地选择策略的同时, 必须深刻领会题意, 构造合理有效的函数 (可以不断尝试, 不断验证) , 才能真正达到运用构造函数策略解题的目的.

四、结束语

数学解题策略是多种多样的, 每种策略作用在不同的对象上都有各自的独特性和高效性, 构造函数这一解题策略也不例外.构造函数解题要求解题者具有敏锐的洞察力和积极的创新意识, 同时还需要一定的解题功底, 因而决定了在付诸应用时可能存在的局限性.在充分考虑构造函数解题策略的局限性的同时, 要发挥主观能动性, 开拓思路, 努力尝试, 在实践中展示这一策略的美感.

参考文献

[1]余元希, 田万海, 毛宏德.初等代数研究 (下) .北京:高等教育出版社.

[2]朱水根, 王延文.中学数学教学导论.北京:教育科学出版社.

篇11:Vlookup函数的用法探析

关键词 参数 Vlookup函数

中图分类号:TP31 文献标识码:A

用户使用函数的过程实际上就是对某个特定区域内的数据进行一个计算的过程。用好函数就是要会用每个函数的语法,本文就在教学过程中对Vlookup函数的理解,对函数的使用方法进行总结和归纳。

Vlookup 函数的语法结构

Vlookup 函数的基本语法格式为:VLOOKUP (lookup_value, table_array, col_index_num, [range _lookup])

VLOOKUP函数的语法中包括下列参数:

Lookup _ value必选。指该函数列表区第一列中要搜索的值。lookup_value参数可以是一个具体的值或引用。如果lookup_value参数的值小于table_array参数列表中第一列的最小值,这时VLOOKUP函数将会返回一个错误值#N/A。

Table_array必选。该参数是指包含数据的列表区域。该参数的表示可以使用区域(例如,A3:D9)或者区域名称的引用方式。Table_array第一列中的值是供lookup_value进行搜索的值。这些值的类型可以是文本、数字或逻辑值(文本不分大小写)。

col_index_num必选。table_array参数列表中必须返回的匹配值所在列的列号。当col_index_num参数为 1 时,则返回table_array参数列表中第一列的值;当col_index_num 为2时,则返回table_array参数列表中第二列的值,依此类推。如果col_index_num参数:小于1时,则VLOOKUP就会返回一个错误值为“#VALUE”。如果大于table_array的列数时,则VLOOKUP就会返回错误值“#REF”。

range_lookup为可选项(根据不同情况可以有该项,也可以没有这项)。它是一个逻辑值,用于指定VLOOKUP在数据列表中查找数据时是精确匹配值还是近似匹配。

Vlookup函数的应用举例。

如(图1)所示要搜索大气特征表的“密度”列以查找“粘度”和“温度”列中对应的值。(该值是在海平面 0 摄氏度或 1 个大气压下对空气的测定。)

图1

公式“ = VLOOKUP(1,A2:C10,2)”使用近似匹配搜索A列中的值 1,在A列中找到小于等于1的最大值0.946,然后返回同一行中B列的值(2.17)。

公式“=VLOOKUP(0.7,A2:C10,3,FALSE)” 使用精确匹配在A列中搜索值0.7。因为A列中没有精确匹配的值,所以返回一个错误值(#N/A)。

如(图2)所示搜索员工表的ID列并查找其他列中的匹配值,以计算年龄并测试错误条件。

图2

公式“ = INT(YEARFRAC(DATE(2004,6,30), VLOOKUP (5,A2:E7,5, FALSE), 1))” 是对 2004 会计年度,查找ID为5的雇员的年龄。使用YEARFRAC函数,将此会计年度的结束日期减去雇员的出生日期,然后使用INT函数将结果以整数形式显示结果(49)。

公式“=IF(ISNA(VLOOKUP(5,A2:E7,2,FALSE))= TRUE, "未发现员工",VLOOKUP(5,A2:E7,2,FALSE))”的意思是如果有ID为15的员工,则显示该员工的姓氏;否则,显示消息“未发现员工”。当VLOOKUP函数返回错误值#NA时,ISNA函数返回值TRUE。该公式运行后返回结果为“未发现员工”。

通过以上的几个实例不难看出。只要把Vlookup函数的语法结构弄明白,可以让它帮助我们在处理事务数据时起到事半功倍的效果。但是在运用Vlookup函数时还应注意其语法使用中参数的以下三个规则:

当在table_array的第一列中搜索文本值时,要保证table_array第一列中的数据不包含前导空格、尾部空格、非打印字符或者未使用不一致的直引号(' 或 ")与弯引号(‘或“)。否则,VLOOKUP可能返回不正确或意外的值。

当在搜索数字或日期值时,要保证table_array第一列中的数据未存储为文本值。否则,VLOOKUP可能返回不正确或意外的值。

如果range_lookup值为FALSE且lookup_value 为文本时,则可以在lookup_value中使用通配符(问号(?)和星号(*)),(问号匹配任意单个字符;星号匹配任意字符序列)。如果要查找的内容是问号或星号时,请在问号或星号前键入波形符(~)。

参考文献

[1] 陈伟.高级办公自动化案例[M].清华大学出版社,2012.

[2] 张勇.计算机应用基础[J].四川教育学院学报,2007.

上一篇:品声初三作文下一篇:新干县首届中小学生法制书画优秀作品展前言