下面是小编帮大家整理的c++面向对象的编程入门篇类构造函数与析构函数,本文共9篇,希望对大家的学习与工作有所帮助。本文原稿由网友“纯情小狗火辣辣”提供。
篇1:c++面向对象的编程入门篇类构造函数与析构函数
我们先说一下什么是构造函数?
上一个教程我们简单说了关于类的一些基本内容,对于类对象成员的初始化我们始终是建立成员函数然后手工调用该函数对成员进行赋值的,那么在c++中对于类来说有没有更方便的方式能够在对象创建的时候就自动初始化成员变量呢,这一点对操作保护成员是至关重要的,答案是肯定的关于c++类成员的初始化,有专门的构造函数来进行自动操作而无需要手工调用,在正式讲解之前先看看c++对构造函数的一个基本定义,
1.C++规定,每个类必须有默认的构造函数,没有构造函数就不能创建对象。
2.若没有提供任何构造函数,那么c++提供自动提供一个默认的构造函数,该默认构造函数是一个没有参数的构造函数,它仅仅负责创建对象而不做任何赋值操作。
3.只要类中提供了任意一个构造函数,那么c++就不在自动提供默认构造函数。
4.类对象的定义和变量的定义类似,使用默认构造函数创建对象的时候,如果创建的是静态或者是全局对象,则对象的位模式全部为0,否则将会是随即的。
我们来看下面的代码:
//程序作者:管宁
//站点:www.cndev-lab.com
//所有稿件均有版权,如要,请务必著名出处和作者
#include
using namespace std;
class Student
{
public:
Student//无参数构造函数
{
number = 1;
score = 100;
}
void show();
protected:
int number;
int score;
};
void Student::show()
{
cout<
}
void main()
{
Student a;
a.show();
cin.get();
}
在类中的定义的和类名相同,并且没有任何返回类型的Student()就是构造函数,这是一个无参数的构造函数,他在对象创建的时候自动调用,如果去掉Student()函数体内的代码那么它和c++的默认提供的构造函数等价的,
构造函数可以带任意多个的形式参数,这一点和普通函数的特性是一样的!
下面我们来看一个带参数的构造函数是如何进行对象的始化操作的。
代码如下:
//程序作者:管宁
//站点:www.cndev-lab.com
//所有稿件均有版权,如要转载,请务必著名出处和作者
#include
using namespace std;
class Teacher
{
public:
Teacher(char *input_name)//有参数的构造函数
{
name=new char[10];
//name=input_name;//这样赋值是错误的
strcpy(name,input_name);
}
void show();
protected:
char *name;
};
void Teacher::show()
{
cout<
}
void main()
{
//Teacher a;//这里是错误的,因为没有无参数的构造函数
Teacher a(“test”);
a.show();
cin.get();
}
我们创建了一个带有字符指针的带有形参的Teacher(char *input_name)的构造函数,调用它创建对象的使用类名加对象名称加扩号和扩号内参数的方式调用,这和调用函数有点类似,但意义也有所不同,因为构造函数是为创建对象而设立的,这里的意义不单纯是调用函数,而是创建一个类对象。
一旦类中有了一个带参数的构造函数而又没无参数构造函数的时候系统将无法创建不带参数的对象,所以上面的代码
Teacher a;
就是错误的!!!
这里还有一处也要注意:
//name=input_name;//这样赋值是错误的
因为name指是指向内存堆区的,如果使用name=input_name;会造成指针指向改变不是指向堆区而是指向栈区,导致在后面调用析构函数delete释放堆空间出错!(析构函数的内容我们后面将要介绍)
如果需要调用能够执行就需要再添加一个没有参数的构造函数
篇2:C++(二) 类的设计,构造函数和析构函数
类是编程人员表达自定义数据类型的C++机制,它和C语言中的结构类似,C++类支持数据抽象和面向对象的程序设计,从某种意义上说,也就是数据类型的设计和实现。
一、类的设计
1.类的声明
class 类名
{
private: //私有
...
public: //公有
...
};
2.类的成员
一般在C++类中,所有定义的变量和函数都是类的成员。如果是变量,我们就叫它数据成员如果是函数,我们就叫它成员函数。
3.类成员的可见性
private和public访问控制符决定了成员的可见性。由一个访问控制符设定的可访问状态将一直持续到下一个访问控制符出现,或者类声明的结束。私有成员仅能被同一个类中的成员函数访问,公有成员既可以被同一类中的成员函数访问,也可以被其他已经实例化的类中函数访问。当然,这也有例外的情况,这是以后要讨论的友元函数。
类中默认的数据类型是private,结构中的默认类型是public。一般情况下,变量都作为私有成员出现,函数都作为公有成员出现。
类中还有一种访问控制符protected,叫保护成员,以后再说明。
4.初始化
在声明一个类的对象时,可以用圆括号()包含一个初始化表。
看下面一个例子:
#include iostream.h
class Box
{
private:
int height,width,depth; //3个私有数据成员
public:
Box(int,int,int);
~Box();
int volume(); //成员函数
};
Box::Box(int ht,int wd,int dp)
{
height=ht;
width=wd;
depth=dp;
}
Box::~Box()
{
//nothing
}
int Box::volume()
{
return height*width*depth;
}
int main()
{
Box thisbox(3,4,5); //声明一个类对象并初始化
cout< return 0;
}
当一个类中没有private成员和protected成员时,也没有虚函数,并且不是从其他类中派生出来的,可以用{}来初始化。(以后再讲解)
5.内联函数
内联函数和普通函数的区别是:内联函数是在编译过程中展开的。通常内联函数必须简短。定义类的内联函数有两种方法:一种和C语言一样,在定义函数时使用关键字inline。如:
inline int Box::volume()
{
return height*width*depth;
}
还有一种方法就是直接在类声明的内部定义函数体,而不是仅仅给出一个函数原型。我们把上面的函数简化一下:
#include iostream.h
class Box
{
private:
int height,width,depth;
public:
Box(int ht,int wd,int dp)
{
height=ht;
width=wd;
depth=dp;
}
~Box();
int volume()
{
return height*width*depth;
}
};
int main()
{
Box thisbox(3,4,5); //声明一个类对象并初始化
cout< return 0;
}
这样,两个函数都默认为内联函数了,
二、构造函数
什么是构造函数?通俗的讲,在类中,函数名和类名相同的函数称为构造函数。上面的Box()函数就是构造函数。C++允许同名函数,也就允许在一个类中有多个构造函数。如果一个都没有,编译器将为该类产生一个默认的构造函数,这个构造函数可能会完成一些工作,也可能什么都不做。
绝对不能指定构造函数的类型,即使是void型都不可以。实际上构造函数默认为void型。
当一个类的对象进入作用域时,系统会为其数据成员分配足够的内存,但是系统不一定将其初始化。和内部数据类型对象一样,外部对象的数据成员总是初始化为0。局部对象不会被初始化。构造函数就是被用来进行初始化工作的。当自动类型的类对象离开其作用域时,所站用的内存将释放回系统。
看上面的例子,构造函数Box()函数接受三个整型擦黑素,并把他们赋值给立方体对象的数据成员。
如果构造函数没有参数,那么声明对象时也不需要括号。
1.使用默认参数的构造函数
当在声明类对象时,如果没有指定参数,则使用默认参数来初始化对象。
#include iostream.h
class Box
{
private:
int height,width,depth;
public:
Box(int ht=2,int wd=3,int dp=4)
{
height=ht;
width=wd;
depth=dp;
}
~Box();
int volume()
{
return height*width*depth;
}
};
int main()
{
Box thisbox(3,4,5); //初始化
Box defaulbox; //使用默认参数
cout< cout<
return 0;
}
2.默认构造函数
没有参数或者参数都是默认值的构造函数称为默认构造函数。如果你不提供构造函数,编译器会自动产生一个公共的默认构造函数,这个构造函数什么都不做。如果至少提供一个构造函数,则编译器就不会产生默认构造函数。
3.重载构造函数
一个类中可以有多个构造函数。这些构造函数必须具有不同的参数表。在一个类中需要接受不同初始化值时,就需要编写多个构造函数,但有时候只需要一个不带初始值的空的Box对象。
#include iostream.h
class Box
{
private:
int height,width,depth;
public:
Box() { //nothing }
Box(int ht=2,int wd=3,int dp=4)
{
height=ht;
width=wd;
depth=dp;
}
~Box();
int volume()
{
return height*width*depth;
}
};
int main()
{
Box thisbox(3,4,5); //初始化
Box otherbox;
therbox=thisbox;
cout< return 0;
}
这两个构造函数一个没有初始化值,一个有。当没有初始化值时,程序使用默认值,即2,3,4。
篇3:编写类String 的构造函数、析构函数和赋值函数
编写类String 的构造函数、析构函数和赋值函数
已知类String 的原型为:
class String
{
public:
String(const char *str = NULL); // 普通构造函数
String(const String &other); // 拷贝构造函数
~ String(void); // 析构函数
String & operate =(const String &other); // 赋值函数
private:
char *m_data; // 用于保存字符串
};
请编写String 的上述4 个函数,
标准答案:
// String 的.析构函数
String::~String(void) // 3 分
{
delete [] m_data;
// 由于m_data 是内部数据类型,也可以写成 delete m_data;
}
// String 的普通构造函数
String::String(const char *str) // 6 分
{
if(str==NULL)
{
m_data = new char[1]; // 若能加 NULL 判断则更好
*m_data = ‘\\0’;
}
else
{
int length = strlen(str);
m_data = new char[length+1]; // 若能加 NULL 判断则更好
strcpy(m_data, str);
}
}
// 拷贝构造函数
String::String(const String &other) // 3 分
{
int length = strlen(other.m_data);
m_data = new char[length+1]; // 若能加 NULL 判断则更好
strcpy(m_data, other.m_data);
}
// 赋值函数
String & String::operate =(const String &other) // 13 分
{
// (1) 检查自赋值 // 4 分
if(this == &other)
return *this;
// (2) 释放原有的内存资源 // 3 分
delete [] m_data;
// (3)分配新的内存资源,并复制内容 // 3 分
int length = strlen(other.m_data);
m_data = new char[length+1]; // 若能加 NULL 判断则更好
strcpy(m_data, other.m_data);
// (4)返回本对象的引用 // 3 分
return *this;
}
篇4:析构函数的奥秘
,
那么,如果我们把main函数改变一下:
int main(int argc, char* argv[])
{
B * b = new C;
delete b;
return 0;
}
请问:这段代码会发生内存泄漏吗?执行结果如下:
Constructor of A
Deconstructor of B
发生了什么?调用了A的构成函数分配了内存,却只调用了B的析构函数,C和A的析构函数都没有调用,内存没有释放,为什么?
有人也许已经看出了问题所在,B和C的析构函数都应该是虚函数,否则,由于b的类型为指向类B的指针,delete b只会调用B的析构函数。当B和C的析构函数都是虚函数时,编译器会根据b指向的对象实际上是C的对象,而去调用C的析构函数。请对代码作如下改变:
class B {
public:
virtual ~B { printf(“Deconstructor of B\\n”); }
};
class C : public B {
public:
virtual ~C () { printf(“Deconstructor of C\\n”); }
private:
A a;
};
再次运行,结果正确:
Constructor of A
Deconstructor of C
Deconstructor of A
Deconstructor of B
篇5:C语言sprintf与sscanf函数
1、前言
我们经常涉及到数字与字符串之间的转换,例如将32位无符号整数的ip地址转换为点分十进制的ip地址字符串,或者反过来,从给定的字符串中提取相关内容,例如给定一个地址:www.bokeyuan.cn:2345,我们要从地址中提出协议,主机地址和端口号。之前对字符串和数字之间的关系不是很熟悉,工作中经常涉及到这个,如是好好总结一下。C语言提供了一些列的格式化输入输出函数,最基本的是面向控制台标准输出和输入的printf和scanf,其实还有面向字符串的sprint和sscanf,面向文件的流的fprintf和fscanf。今天着重总结一下sprintf和sscanf系列函数,这两个函数类似于scanf和printf ,不同点是从字符串*buffer用于输入输出。
2、sprintf函数
sprintf函数原型为 int sprintf(char *str, const char *format, ...)。作用是格式化字符串,具体功能如下所示:
(1)将数字变量转换为字符串。
(2)得到整型变量的16进制和8进制字符串。
(3)连接多个字符串。
举例如下所示:
1 char str[256] = { 0 };
2 int data = 1024;
3 //将data转换为字符串
4 sprintf(str,“%d”,data);
5 //获取data的十六进制
6 sprintf(str,“0x%X”,data);
7 //获取data的八进制
8 sprintf(str,“0%o”,data);
9 const char *s1 = “Hello”;
10 const char *s2 = “World”;
11 //连接字符串s1和s2
12 sprintf(str,“%s %s”,s1,s2);
3、sscanf函数
sscanf函数原型为int sscanf(const char *str, const char *format, ...)。将参数str的字符串根据参数format字符串来转换并格式化数据,转换后的结果存于对应的参数内。具体功能如下:
(1)根据格式从字符串中提取数据。如从字符串中取出整数、浮点数和字符串等。
(2)取指定长度的字符串
(3)取到指定字符为止的字符串
(4)取仅包含指定字符集的字符串
(5)取到指定字符集为止的字符串
sscanf可以支持格式字符%[]:
(1)-: 表示范围,如:%[1-9]表示只读取1-9这几个数字 %[a-z]表示只读取a-z小写字母,类似地 %[A-Z]只读取大写字母
(2)^: 表示不取,如:%[^1]表示读取除'1'以外的所有字符 %[^/]表示除/以外的所有字符
(3),: 范围可以用“,”相连接 如%[1-9,a-z]表示同时取1-9数字和a-z小写字母
(4)原则:从第一个在指定范围内的数字开始读取,到第一个不在范围内的数字结束%s 可以看成%[] 的一个特例 %[^ ](注意^后面有一个空格!)
解析网址的例子如下所示:
1 const char *s = “www.baidu.com:1234”;
2 char protocol[32] = { 0 };
3 char host[128] = { 0 };
4 char port[8] = { 0 };
5 sscanf(s,“%[^:]://%[^:]:%[1-9]”,protocol,host,port);
6
7 printf(“protocol: %s\\n”,protocol);
8 printf(“host: %s\\n”,host);
9 printf(“port: %s\\n”,port);
10
4、snprintf函数
snprintf函数是sprintf函数的更加安全版本,考虑到字符串的字节数,防止了字符串溢出。函数形式为:int snprintf(char *restrict buf, size_t n, const char * restrict format, ...);。最多从源串中拷贝n-1个字符到目标串中,然后再在后面加一个0。所以如果目标串的大小为n 的话,将不会溢出。
5、测试程序
本次采用ip地址和整型之间的转换,mac地址转换作为测试程序,整个程序如下所示:
1 #include
2 #include
3
4 #define IP_STR_LEN 18
5 #define MAC_STR_LEN 18
6 #define MAC_BIT_LEN 6
7 #define LITTLE_ENDIAN 0
8 #define BIG_ENDIAN 1
9
10 typedef unsigned char uchar;
11 typedef unsigned int uint;
12
13 int big_little_endian()
14 {
15 int data = 0x1;
16 if (*((char*)&data) == 0x1)
17 return LITTLE_ENDIAN;
18 return BIG_ENDIAN;
19 }
20
21 uint ipstr2int(const char * ipstr)
22 {
23 assert(ipstr);
24 uint a,b,c,d;
25 uint ip = 0;
26 sscanf(ipstr,“%u.%u.%u.%u”,&a,&b,&c,&d);
27 a = (a << 24) ;
28 b = (b << 16) ;
29 c = (c << 8) ;
30 d = (d << 0) ;
31 ip = a | b | c | d;
32 return ip;
33 }
34
35 char *int2ipstr(const uint ip, char *ipstr, const uint ip_str_len)
36 {
37 assert(ipstr);
38 if (big_little_endian() == LITTLE_ENDIAN)
39 sprintf(ipstr,“%u.%u.%u.%u”,
40 (uchar)*((char*)(&ip)+3),
41 (uchar)*((char*)(&ip)+2),
42 (uchar)*((char*)(&ip)+1),
43 (uchar)*((char*)(&ip)+0));
44 else
45 sprintf(ipstr,“%u.%u.%u.%u”,
46 (uchar)*((char*)(&ip)+0),
47 (uchar)*((char*)(&ip)+1),
48 (uchar)*((char*)(&ip)+2),
49 (uchar)*((char*)(&ip)+3));
50
51 return ipstr;
52 }
53
55 char *mac2str(const unsigned char *mac,char *mac_str,const uint mac_str_len)
56 {
57 assert(mac_str);
58 sprintf(mac_str,“%02X-%02X-%02X-%02X-%02X-%02X”,
59 mac[0],mac[1],mac[2],
60 mac[3],mac[4],mac[5]);
61 }
62
63 int main()
64 {
65 char ip_str[IP_STR_LEN] = {0};
66 char mac_str[MAC_STR_LEN] = {0};
67 unsigned char mac[MAC_BIT_LEN] = {0XEF,0XAD,0XF4,0X4F,0XAA,0X0F};
68 const char *ipstr = “10.0.3.193”;
69 unsigned int ip;
70 int2ipstr(167773121,ip_str,IP_STR_LEN);
篇6:(C语言)字符串比较函数,指针数组与数组指针
问题描述:
写一个函数,用于比较两个字符串的比较(string_compare).
程序分析:
(1)主要思想:传入两个字符串后,比较这两个字符串中的每个元素,如果第一次比较就不相等,就不要让它进入到下面的比较中,这样一来,将它返回一个相减的值(即:两数组中开始不相等的那两个元素相减,返回值(int类型),是ASCII码值相减)。进入比较的过程中时,相等就返回0;其他情况都返回那个相减的值。
(2)主要方式:定义指针数组,并对其初始化。然后照上面的思想,进行代码的实现。
代码如下:
/***指针数组(1)int *a[10] 是一个指针数组--->是一个数组(每个数组中的元素都是int*类型)(2)int (*a)[10] 是一个数组指针--->指向一个数组(十个int类型的数组) 注意:*,[],的优先级依次递增。下面使用了指针数组的例子,至于数组指针。。**/#include
篇7:Python类方法init和del构造、析构过程分析
这篇文章主要介绍了Python类方法__init__和__del__构造、析构过程分析,本文分析了什么时候构造、什么时候析构、成员变量如何处理、Python中的共享成员函数如何访问等问题,需要的朋友可以参考下
最近学习《Python参考手册》学到Class部分,遇到了类的构造析构部分的问题:
1、什么时候构造?
2、什么时候析构?
3、成员变量如何处理?
4、Python中的共享成员函数如何访问?
------------------------
探索过程:
1、经过查找,Python中没有专用的构造和析构函数,但是一般可以在__init__和__del__分别完成初始化和删除操作,可用这个替代构造和析构,还有一个__new__用来定制类的创建过程,不过需要一定的配置,此处不做讨论。
2、类的成员函数默认都相当于是public的,但是默认开头为__的为私有变量,虽然是私有,但是我们还可以通过一定的手段访问到,即Python不存在真正的私有变量。如:
代码如下:
__priValue = 0 # 会自动变形为“_类名__priValue”的成员变量
3、由于Python的特殊性,全局成员变量是共享的,所以类的实例不会为它专门分配内容空间,类似于static,具体使用参看下面的例子。
测试1:
代码如下:
# encoding:utf8
class NewClass(object):
num_count = 0 # 所有的实例都共享此变量,即不单独为每个实例分配
def __init__(self,name):
self.name = name
NewClass.num_count += 1
print name,NewClass.num_count
def __del__(self):
NewClass.num_count -= 1
print “Del”,self.name,NewClass.num_count
def test():
print “aa”
aa = NewClass(“Hello”)
bb = NewClass(“World”)
cc = NewClass(“aaaa”)
print “Over”
调试运行:
代码如下:
Hello 1
World 2
aaaa 3
Over
DeException l Hello 2
AttributeError: “‘NoneType‘ object has no attribute ‘num_count‘” in
Exception AttributeError: “‘NoneType‘ object has no attribute ‘num_count‘” in
我们发现,num_count 是全局的,当每创建一个实例,__init__()被调用,num_count 的值增一,当程序结束后,所有的实例会被析构,即调用__del__() 但是此时引发了异常。查看异常为 “NoneType” 即 析构时NewClass 已经被垃圾回收,所以会产生这样的异常。
但是,疑问来了?为什么会这样?按照C/C++等语言的经验,不应该这样啊!经过查找资料,发现:
Python的垃圾回收过程与常用语言的不一样,Python按照字典顺序进行垃圾回收,而不是按照创建顺序进行。所以当系统进行回收资源时,会按照类名A-Za-z的顺序,依次进行,我们无法掌控这里的流程。
明白这些,我们做如下尝试:
代码如下:
# encoding:utf8
class NewClass(object):
num_count = 0 # 所有的实例都共享此变量,即不单独为每个实例分配
def __init__(self,name):
self.name = name
NewClass.num_count += 1
print name,NewClass.num_count
def __del__(self):
NewClass.num_count -= 1
print “Del”,self.name,NewClass.num_count
def test():
print “aa”
aa = NewClass(“Hello”)
bb = NewClass(“World”)
cc = NewClass(“aaaa”)
del aa
del bb
del cc
print “Over”
调试输出:
代码如下:
Hello 1
World 2
aaaa 3
Del Hello 2
Del World 1
Del aaaa 0
Over
OK,一切按照我们预料的顺序发生,
但是,我们总不能每次都手动回收吧?这么做Python自己的垃圾回收还有什么意义?
SO,继续查找,我们还可以通过self.__class__访问到类本身,然后再访问自身的共享成员变量,即 self.__class__.num_count , 将类中的NewClass.num_count替换为self.__class__.num_count 编译运行,如下:
代码如下:
# encoding:utf8
class NewClass(object):
num_count = 0 # 所有的实例都共享此变量,即不单独为每个实例分配
def __init__(self,name):
self.name = name
self.__class__.num_count += 1
print name,NewClass.num_count
def __del__(self):
self.__class__.num_count -= 1
print “Del”,self.name,self.__class__.num_count
def test():
print “aa”
aa = NewClass(“Hello”)
bb = NewClass(“World”)
cc = NewClass(“aaaa”)
print “Over”
结果:
代码如下:
Hello 1
World 2
aaaa 3
Over
Del Hello 2
Del World 1
Del aaaa 0
Perfect!我们完美地处理了这个问题!
PS:
书上又提到了一些问题,在这里作补充(仅作为参考):
__new__()是唯一在实例创建之前执行的方法,一般用在定义元类时使用。
del xxx 不会主动调用__del__方法,只有引用计数==0时,__del__()才会被执行,并且定义了__del_()的实例无法被Python的循环垃圾收集器收集,所以尽量不要自定义__del__()。一般情况下,__del__() 不会破坏垃圾处理器。
实验中发现垃圾回收自动调用了__del__, 这与书上所说又不符,不知是什么原因,需要继续学习。
篇8:C语言函数教学设计与实践论文
C语言函数教学设计与实践论文
一、函数在C语言程序设计课程中的地位
函数部分的学习被安排在三大程序控制结构之后,有利于学生对函数知识点的系统学习,也能够使学生深刻理解结构化程序设计的全局思想,在大学期间开设《C语言程序设计》课程的主要目的是培养学生充分利用信息时代的优势,通过编程解决实际问题的能力。实际上C程序的基本组成单位是函数,课程所有知识点的学习最终都将落实到编写各种函数来进行验证和实现。因此,学生只有灵活掌握函数的运用,才能为后续学习奠定坚实基础。
二、传统函数教学存在的问题
传统函数教学流程如下:
其一,函数定义及其形式;
其二,函数形参,return语句,函数返回值;
其三,函数声明,格式,位置;
其四,函数调用,函数实参等。这种传统的教学流程过于强调函数语法知识,概念和规则的讲解,这样导致学生似懂非懂,与教学理念相违背,为了适应教学要求,突出以学生为主,教员为辅的教学理念,主要探讨函数的教学设计及实践[1]。
三、新的函数教学设计及方法
函数教学主要以发现问题、分析问题、解决问题为思路开展教学,以启发、引导、对比和总结为辅帮助学生分析问题解决提出的问题。不仅可以让学生带着兴趣学习,也会加深学生对知识点的深刻理解及灵活应用。本堂课的教学流程是:交代任务;提出问题、发现问题、解决问题;巩固练习[2]。
第一,提出问题、分析问题、解决问题。学生只学过在main函数中编写简单程序,于是向学生抛出问题:复杂程序应如何进行组织和设计?在此,给学生一些时间利用main函数来解决给定任务,解决完毕和同学生一起验证结果,然后引导学生分析这种解决方式在实际中存在的.问题,并启发学生思考解决此问题的最佳方法,从而引出学习的内容——函数法。接着再次引导学生用函数法重新解决给定的任务,最后将解决该任务的两种方法进行对比,让学生讨论、体会并总结出复杂程序的设计方法。
第二,巩固练习。在这个环节,笔者设计了带有陷阱的小例子:通过编写swap函数来实现主函数中两个整数的交换,给学生一些时间讨论、验证结果,引导学生分析其中的问题,同时引出函数调用流程这一知识点,并通过动画演示的方式帮助学生分析函数调用流程。
四、函数教学实践
第一,利用结构化程序设计原则设计复杂程序。在main函数中编程解决问题的基础上引导学生独立解决给定任务,发现大部分学生都能很好地编写出程序,让学生观察上述代码,联系实际启发引导学生讨论并总结出如下问题:
其一,代码冗余;
其二,不易维护;
其三,可靠性差;
其四,可读性差。
在此基础上启发学生剖析问题并让学生给出解决方案,即main函数没有能力独自解决整个任务,这样很自然引出复杂C程序组织和设计的原则:自顶向下,逐步细化,模块化设计,结构化编码。在这一原则的指导下,人们可以将任意复杂任务分解若干子任务。程序设计时每个子任务看成独立模块,每个程序设计人员分别完成一个或多个模块。人们称这样的程序设计方法为“模块法”,在编写代码时每个模块对应编写一个函数。最后选择一种结构化语言对各个函数进行编码,然后在机器上反复调试修改验证。函数定义形式函数首部函数体含义作用及功能功能具体实现对应知识点函数名,函数形参,返回值如:longfact(intm)声明语句,执行语句第二,函数定义及调用。
其一,函数定义形式;
其二,函数调用。通过知识迁移将以前学过的使用库函数的语句引导学生总结出函数调用的形式:①无返回值;②带返回值。在此,详细讲解实参与形参的区别及联系,接着给学生一些时间利用函数调用的方法改写程序并将两种解决问题的方法进行对比,让学生观察总结出程序模块化的优点。
第三,进阶练习。布置小任务:编写swap函数来实现main函数中两个整数交换。在学生编写时,教员应根据每位学生的情况进行适当指导提示,并及时纠正学生们共性的错误。提示学生思考计算机本身是如何执行程序中的main和swap函数的,引导学生回答并指正。通过画图这种直观的方式,让学生理解函数调用的执行流程,同时也加深了学生对函数模块独立性的深刻理解,将抽象的知识变得通俗易懂。
五、结束语
综上所述,C语言中函数涉及的知识杂而多样,在教学中采用启发、引导、对比等多种教学方法,不拘泥于知识点的讲解,而是从程序设计全局角度出发,以分工合作思想为切入点,探讨了现实中复杂程序编写多个函数来实现的必要性,发现问题,解决问题,让学生主动学习的思路展开,实践证明该思路符合学生接受知识的思维习惯,这不仅很好地调动学生学习的积极性,从而培养了学生独立思考解决问题的能力。
参考文献:
[1]谭浩强.C程序设计第三版,北京清华大学出版社.
[2]高等教育出版社.c语言程序设计版,高等教育出版社.
篇9:Python多线程编程(三):threading.Thread类的重要函数和方法
这篇文章主要介绍了Python多线程编程(三):threading.Thread类的重要函数和方法,本文讲解了线程名称、join方法、setDaemon方法等内容,需要的朋友可以参考下
这篇文章主要介绍threading模块中的主类Thread的一些主要方法,实例代码如下:
代码如下:
‘‘‘
Created on 2012-9-7
@author: walfred
@module: thread.ThreadTest3
@description:
‘‘‘
import threading
class MyThread(threading.Thread):
def __init__(self):
threading.Thread.__init__(self)
def run(self):
print “I am %s” % (self.name)
if __name__ == “__main__”:
for i in range(0, 5):
my_thread = MyThread()
my_thread.start()
name相关
你可以为每一个thread指定name,默认的是Thread-No形式的,如上述实例代码打印出的一样:
代码如下:
I am Thread-1
I am Thread-2
I am Thread-3
I am Thread-4
I am Thread-5
当然你可以指定每一个thread的name,这个通过setName方法,代码:
代码如下:
def __init__(self):
threading.Thread.__init__(self)
self.setName(“new” + self.name)
join方法
join方法原型如下,这个方法是用来阻塞当前上下文,直至该线程运行结束:
代码如下:
def join(self, timeout=None):
timeout可以设置超时
timeout可以设置超时蚕食
setDaemon方法
当我们在程序运行中,执行一个主线程,如果主线程又创建一个子线程,主线程和子线程就分兵两路,当主线程完成想退出时,会检验子线程是否完成,
Python多线程编程(三):threading.Thread类的重要函数和方法
,
如果子线程未完成,则主线程会等待子线程完成后再退出。但是有时候我们需要的是,只要主线程完成了,不管子线程是否完成,都要和主线程一起退出,这时就可以用setDaemon方法,并设置其参数为True。
当然这上面列举的只是我们在编程是经常使用到的方法,更多方法,可以参见:Higher-level threading interface