析构函数与构造函数与析构函数的区别

Posts - 90,
Articles - 0,
Comments - 513
求真、务实。
23:45 by wid, ... 阅读,
学习C++ -& 构造函数与析构函数
一、构造函数的介绍&& &1. 构造函数的作用&& &&& &构造函数主要用来在创建对象时完成对对象属性的一些初始化等操作, 当创建对象时, 对象会自动调用它的构造函数。一般来说, 构造函数有以下三个方面的作用:&& &&& &&& &■ 给创建的对象建立一个标识符;&& &&& &&& &■ 为对象数据成员开辟内存空间;&& &&& &&& &■ 完成对象数据成员的初始化。&& &&& &&& &2. 默认构造函数&& &&& &当用户没有显式的去定义构造函数时, 编译器会为类生成一个默认的构造函数, 称为 "默认构造函数", 默认构造函数不能完成对象数据成员的初始化, 只能给对象创建一标识符, 并为对象中的数据成员开辟一定的内存空间。&& &&& &&& &3. 构造函数的特点&& &&& &无论是用户自定义的构造函数还是默认构造函数都主要有以下特点:&& &&& &&& &①. 在对象被创建时自动执行;&& &&& &&& &②. 构造函数的函数名与类名相同;&& &&& &&& &③. 没有返回值类型、也没有返回值;&& &&& &&& &④. 构造函数不能被显式调用。&& &&& &&& &
#给Python程序员的注释: C++中的构造函数类似于Python中的 __init__ 方法.
&& &&& &&& &&& &&& &&& &&& &&& &二、构造函数的显式定义&& &由于在大多数情况下我们希望在对象创建时就完成一些对成员属性的初始化等工作, 而默认构造函数无法满足我们的要求, 所以我们需要显式定义一个构造函数来覆盖掉默认构造函数以便来完成必要的初始化工作, 当用户自定义构造函数后编译器就不会再为对象生成默认构造函数。&& &&& &在构造函数的特点中我们看到, 构造函数的名称必须与类名相同, 并且没有返回值类型和返回值, 看一个构造函数的定义:
#include &iostream&
using namespace
class Point
//声明并定义构造函数
cout&&"自定义的构造函数被调用...\n";
xPos = 100;
//利用构造函数对数据成员 xPos, yPos进行初始化
yPos = 100;
void printPoint()
cout&&"xPos = " && xPos &&
cout&&"yPos = " && yPos &&
int main()
//创建对象M
M.printPoint();
&&& &编译运行的结果:
自定义的构造函数被调用...
xPos = 100
yPos = 100
Process returned 0 (0x0)
execution time : 0.453 s
Press any key to continue.
&& &代码说明:&& &&& &在Point类的 public 成员中我们定义了一个构造函数 Point() , 可以看到这个Point构造函数并不像 printPoint 函数有个void类型的返回值, 这正是构造函数的一特点。在构造函数中, 我们输出了一句提示信息, "自定义的构造函数被调用...", 并且将对象中的数据成员xPos和yPos初始化为100。&& &&& &&& &&& &在 main 函数中, 使用 Point 类创建了一个对象 M, 并调用M对象的方法 printPoint 输出M的属性信息, 根据输出结果看到, 自定义的构造函数被调用了, 所以 xPos和yPos 的值此时都是100, 而不是一个随机值。&& &&& &&& &&& &需要提示一下的是, 构造函数的定义也可放在类外进行。&& &&& &&& &&& &&& &&& &
&& &&& &三、有参数的构造函数&& &在上个示例中实在构造函数的函数体内直接对数据成员进行赋值以达到初始化的目的, 但是有时候在创建时每个对象的属性有可能是不同的, 这种直接赋值的方式显然不合适。不过构造函数是支持向函数中传入参数的, 所以可以使用带参数的构造函数来解决该问题。&& &
#include &iostream&
using namespace
class Point
Point(int x = 0, int y = 0)
//带有默认参数的构造函数
cout&&"自定义的构造函数被调用...\n";
//利用传入的参数值对成员属性进行初始化
void printPoint()
cout&&"xPos = " && xPos &&
cout&&"yPos = " && yPos &&
int main()
Point M(10, 20);
//创建对象M并初始化xPos,yPos为10和20
M.printPoint();
Point N(200);
//创建对象N并初始化xPos为200, yPos使用参数y的默认值0
N.printPoint();
//创建对象P使用构造函数的默认参数
P.printPoint();
&&& &编译运行的结果:
自定义的构造函数被调用...
自定义的构造函数被调用...
xPos = 200
自定义的构造函数被调用...
Process returned 0 (0x0)
execution time : 0.297 s
Press any key to continue.
&& &代码说明:&& &&& &在这个示例中的构造函数 Point(int x = 0, int y = 0) 使用了参数列表并且对参数进行了默认参数设置为0。在 main 函数中共创建了三个对象 M, N, P。&& &&& &&& &M对象不使用默认参数将M的坐标属性初始化10和20;&& &&& &&& &N对象使用一个默认参数y, xPos属性初始化为200;&& &&& &&& &P对象完全使用默认参数将xPos和yPos初始化为0。&& &&& &&& &&& &&& &&& &
&& &&& &&& &三、构造函数的重载&& &构造函数也毕竟是函数, 与普通函数相同, 构造函数也支持重载, 需要注意的是, 在进行构造函数的重载时要注意重载和参数默认的关系要处理好, 避免产生代码的二义性导致编译出错, 例如以下具有二义性的重载:&& &
Point(int x = 0, int y = 0)
//默认参数的构造函数
//重载一个无参构造函数
&& &&&& && &在上面的重载中, 当尝试用 Point 类重载一个无参数传入的对象 M 时, Point M; 这时编译器就报一条 error: call of overloaded 'Point()' is ambiguous 的错误信息来告诉我们说 Point 函数具有二义性, 这是因为 Point(int x = 0, int y = 0) 全部使用了默认参数, 即使我们不传入参数也不会出现错误, 但是在重载时又重载了一个不需要传入参数了构造函数 Point(), 这样就造成了当创建对象都不传入参数时编译器就不知道到底该使用哪个构造函数了, 就造成了二义性。&& &&& &&& &
四、初始化表达式&& &对象中的一些数据成员除了在构造函数体中进行初始化外还可以通过调用初始化表来进行完成, 要使用初始化表来对数据成员进行初始化时使用 : 号进行调出, 示例如下:&& &
Point(int x = 0, int y = 0):xPos(x), yPos(y)  //使用初始化表
cout&&"调用初始化表对数据成员进行初始化!\n";
&& &&&& && &在 Point 构造函数头的后面, 通过单个冒号 : 引出的就是初始化表, 初始化的内容为 Point 类中int型的 xPos 成员和 yPos成员, 其效果和 xPos = yPos = 是相同的。&& &&& &与在构造函数体内进行初始化不同的是, 使用初始化表进行初始化是在构造函数被调用以前就完成的。每个成员在初始化表中只能出现一次, 并且初始化的顺序不是取决于数据成员在初始化表中出现的顺序, 而是取决于在类中声明的顺序。&& &&& &此外, 一些通过构造函数无法进行初始化的数据类型可以使用初始化表进行初始化, 如: 常量成员和引用成员, 这部分内容将在后面进行详细说明。使用初始化表对对象成员进行初始化的完整示例:&& &
#include &iostream&
using namespace
class Point
Point(int x = 0, int y = 0):xPos(x), yPos(y)
cout&&"调用初始化表对数据成员进行初始化!\n";
void printPoint()
cout&&"xPos = " && xPos &&
cout&&"yPos = " && yPos &&
int main()
Point M(10, 20);
//创建对象M并初始化xPos,yPos为10和20
M.printPoint();
&& &五、析构函数&& &与构造函数相反, 析构函数是在对象被撤销时被自动调用, 用于对成员撤销时的一些清理工作, 例如在前面提到的手动释放使用 new 或 malloc 进行申请的内存空间。析构函数具有以下特点:&& &&& &■ 析构函数函数名与类名相同, 紧贴在名称前面用波浪号 ~ 与构造函数进行区分, 例如: ~Point();&& &&& &■ 构造函数没有返回类型, 也不能指定参数, 因此析构函数只能有一个, 不能被重载;&& &&& &■ 当对象被撤销时析构函数被自动调用, 与构造函数不同的是, 析构函数可以被显式的调用, 以释放对象中动态申请的内存。
#给Python程序员的注释: C++中的析构函数类似于Python中的 __del__ 方法.
&& &当用户没有显式定义析构函数时, 编译器同样会为对象生成一个默认的析构函数, 但默认生成的析构函数只能释放类的普通数据成员所占用的空间, 无法释放通过 new 或 malloc 进行申请的空间, 因此有时我们需要自己显式的定义析构函数对这些申请的空间进行释放, 避免造成内存泄露。
1 #include &iostream&
#include &cstring&
using namespace
class Book
Book( const char *name )
//构造函数
bookName = new char[strlen(name)+1];
strcpy(bookName, name);
//析构函数
cout&&"析构函数被调用...\n";
delete []bookN
//释放通过new申请的空间
void showName() { cout&&"Book name: "&& bookName && }
char *bookN
int main()
Book CPP("C++ Primer");
CPP.showName();
&&& 编译运行的结果:
Book name: C++ Primer
析构函数被调用...
Process returned 0 (0x0)
execution time : 0.266 s
Press any key to continue.
&& &代码说明:&& &&& &代码中创建了一个 Book 类, 类的数据成员只有一个字符指针型的 bookName, 在创建对象时系统会为该指针变量分配它所需内存, 但是此时该指针并没有被初始化所以不会再为其分配其他多余的内存单元。在构造函数中, 我们使用 new 申请了一块 strlen(name)+1 大小的空间, 也就是比传入进来的字符串长度多1的空间, 目的是让字符指针 bookName 指向它, 这样才能正常保存传入的字符串。&& &&& &&& &&& &在 main 函数中使用 Book 类创建了一个对象 CPP, 初始化 bookName 属性为 "C++ Primer"。从运行结果可以看到, 析构函数被调用了, 这时使用 new 所申请的空间就会被正常释放。&& &&& &&& &&& &自然状态下对象何时将被销毁取决于对象的生存周期, 例如全局对象是在程序运行结束时被销毁, 自动对象是在离开其作用域时被销毁。 && &&& &&& &如果需要显式调用析构函数来释放对象中动态申请的空间只需要使用 对象名.析构函数名(); 即可, 例如上例中要显式调用析构函数来释放 bookName 所指向的空间只要:
CPP.~Book();
--------------------温馨提示!由于新浪微博认证机制调整,您的新浪微博帐号绑定已过期,请重新绑定!&&|&&
爱喝茶/也爱咖啡可乐
爱动运更爱睡觉/沉默而爱憎分明
爱挑战/爱钻研
爱电影和音乐/爱生活不爱黑眼圈
我崇尚简单和懒惰/
我是IT江湖的小浪花...
LOFTER精选
网易考拉推荐
用微信&&“扫一扫”
将文章分享到朋友圈。
用易信&&“扫一扫”
将文章分享到朋友圈。
阅读(3691)|
用微信&&“扫一扫”
将文章分享到朋友圈。
用易信&&“扫一扫”
将文章分享到朋友圈。
历史上的今天
loftPermalink:'',
id:'fks_',
blogTitle:'构造函数和析构函数的功能和特点',
blogAbstract:'&& 构造函数和析构函数是在类体中说明的两种特殊的成员函数。&&& 构造函数的功能是在创建对象时,使用给定的值来将对象初始化。&&& 析构函数的功能是用来释放一个对象的。在对象删除前,用它来做一些清理工作,它与构造函数的功能正好相反。
构造函数的特点如下:&&& (1)构造函数是成员函数,函数体可写在类体内,也可写在类体外。&&& (2)构造函数是一个特殊的函数,该函数的名字与类名相同,该函数不指定类型说明,它有隐含的返回值,该值由系统内部使用。该函数可以有一个参数,也可以有多个参数。&&& (3)构造函数可以重载,即可以定义多个参数个数不同的函数。&&& (4)程序中不能直接调用构造函数,在创建对象时系统自动调用构造函数。&&& 析构函数的特点如下:',
blogTag:'',
blogUrl:'blog/static/',
isPublished:1,
istop:false,
modifyTime:0,
publishTime:9,
permalink:'blog/static/',
commentCount:1,
mainCommentCount:1,
recommendCount:3,
bsrk:-100,
publisherId:0,
recomBlogHome:false,
currentRecomBlog:false,
attachmentsFileIds:[],
groupInfo:{},
friendstatus:'none',
followstatus:'unFollow',
pubSucc:'',
visitorProvince:'',
visitorCity:'',
visitorNewUser:false,
postAddInfo:{},
mset:'000',
remindgoodnightblog:false,
isBlackVisitor:false,
isShowYodaoAd:true,
hostIntro:'爱喝茶/也爱咖啡可乐
\r\n爱动运更爱睡觉/沉默而爱憎分明
\r\n爱挑战/爱钻研
爱电影和音乐/爱生活不爱黑眼圈
\r\n我崇尚简单和懒惰/
\r\n我行我素/
我是IT江湖的小浪花...',
hmcon:'1',
selfRecomBlogCount:'0',
lofter_single:''
{list a as x}
{if x.moveFrom=='wap'}
{elseif x.moveFrom=='iphone'}
{elseif x.moveFrom=='android'}
{elseif x.moveFrom=='mobile'}
${a.selfIntro|escape}{if great260}${suplement}{/if}
{list a as x}
推荐过这篇日志的人:
{list a as x}
{if !!b&&b.length>0}
他们还推荐了:
{list b as y}
转载记录:
{list d as x}
{list a as x}
{list a as x}
{list a as x}
{list a as x}
{if x_index>4}{break}{/if}
${fn2(x.publishTime,'yyyy-MM-dd HH:mm:ss')}
{list a as x}
{if !!(blogDetail.preBlogPermalink)}
{if !!(blogDetail.nextBlogPermalink)}
{list a as x}
{if defined('newslist')&&newslist.length>0}
{list newslist as x}
{if x_index>7}{break}{/if}
{list a as x}
{var first_option =}
{list x.voteDetailList as voteToOption}
{if voteToOption==1}
{if first_option==false},{/if}&&“${b[voteToOption_index]}”&&
{if (x.role!="-1") },“我是${c[x.role]}”&&{/if}
&&&&&&&&${fn1(x.voteTime)}
{if x.userName==''}{/if}
网易公司版权所有&&
{list x.l as y}
{if defined('wl')}
{list wl as x}{/list}void __construct ([ mixed $args [, $... ]] )
PHP 5 允行开发者在一个类中定义一个方法作为构造函数。具有构造函数的类会在每次创建新对象时先调用此方法,所以非常适合在使用对象之前做一些初始化工作。
Note: 如果子类中定义了构造函数则不会隐式调用其父类的构造函数。要执行父类的构造函数,需要在子类的构造函数中调用 parent::__construct()。如果子类没有定义构造函数则会如同一个普通的类方法一样从父类继承(假如没有被定义为 private 的话)。
Example#1使用新标准的构造函数
复制代码 代码如下:
& ?php class BaseClass { && function __construct() { &&&&&& print "In BaseClass constructor\n"; && } } & class SubClass extends BaseClass { && function __construct() { &&&&&& parent::__construct(); &&&&&& print "In SubClass constructor\n"; && } } & class OtherSubClass extends BaseClass { &&& // inherits BaseClass's constructor } & // In BaseClass constructor $obj = new BaseClass(); & // In BaseClass constructor // In SubClass constructor $obj = new SubClass(); & // In BaseClass constructor $obj = new OtherSubClass(); ?&
output: In BaseClass constructor In BaseClass constructor In SubClass constructor In BaseClass constructor
为了实现向后兼容性,如果 PHP 5 在类中找不到 __construct() 函数并且也没有从父类继承一个的话,它就会尝试寻找旧式的构造函数,也就是和类同名的函数。因此唯一会产生兼容性问题的情况是:类中已有一个名为 __construct() 的方法却被用于其它用途时。
与其它方法不同,当 __construct() 被与父类 __construct() 具有不同参数的方法覆盖时,PHP 不会产生一个 E_STRICT 错误信息。
自 PHP 5.3.3 起,在命名空间中,与类名同名的方法不再作为构造函数。这一改变不影响不在命名空间中的类。
Example#2 Constructors in namespaced classes
复制代码 代码如下:
& ?php namespace F class Bar { &&& public function Bar() { &&&&&&& // treated as constructor in PHP 5.3.0-5.3.2 &&&&&&& // treated as regular method as of PHP 5.3.3 &&& } } ?&
void __destruct(void)
PHP 5 引入了析构函数的概念,这类似于其它面向对象的语言,如 C++。析构函数会在到某个对象的所有引用都被删除或者当对象被显式销毁时执行。
Example#3析构函数示例
复制代码 代码如下:
& ?php class MyDestructableClass { && function __construct() { &&&&&& print "In constructor\n"; &&&&&& $this-&name = "MyDestructableClass"; && }
&& function __destruct() { &&&&&& print "Destroying " . $this-&name . "\n"; && } }
$obj = new MyDestructableClass(); ?&
和构造函数一样,父类的析构函数不会被引擎暗中调用。要执行父类的析构函数,必须在子类的析构函数体中显式调用 parent::__destruct()。此外也和构造函数一样,子类如果自己没有定义析构函数则会继承父类的。
析构函数即使在使用 exit() 终止脚本运行时也会被调用。在析构函数中调用 exit() 将会中止其余关闭操作的运行。
阅读(...) 评论()& 鸡啄米:C++编程入门系列之十四(类与对象:构造函数和析构函数)
鸡啄米:C++编程入门系列之十四(类与对象:构造函数和析构函数)
&&&&&&&鸡啄米上一节中给大家讲解了,今天鸡啄米给大家讲C++编程入门时同样必须掌握的构造函数和析构函数。从上一讲开始已经涉及到了很多面向对象设计的细节,大家慢慢跟着学习思考吧,实际上跟我们现实中的很多做事的思想是一致的,这也正是面向对象语言的特点,它是以现实中的事物和围绕事物处理问题的思路为基础的。&&&&&&&某个类的对象之间都有哪些不同呢?首先是对象名不同,其次就是对象的数据成员的值不同。我们在声明一个对象时,也可以同时给它的数据成员赋初值,称为对象的初始化。&&&&&&&1.构造函数&&&&&&&我们在声明一个变量时,如果对它进行了初始化,那么在为此变量分配内存空间时还会向内存单元中写入变量的初始化。声明对象有相似的过程,程序执行时遇到对象声明语句时会向操作系统申请一定的内存空间来存放这个对象,但是它能像一般变量那样初始化时写入指定的初始值吗?类的对象太复杂了,要实现这一点不太容易,这就需要构造函数来实现。&&&&&&&构造函数的作用就是在对象被创建时利用特定的初始值构造对象,把对象置于某一个初始状态,它在对象被创建的时候由系统自动调用,我们只需要使用默认的构造函数或者自己定义构造函数,而不用管怎么调用的。&&&&&& 构造函数也是类的成员函数,除了有成员函数的所有特征外,还有一些不同之处:构造函数的函数名跟类名一样,而且没有返回值。构造函数一般被声明为公有函数,除非我们不允许某个类生成对象则将它声明为private或protected属性。编译器碰到对象声明语句时,会自动生成对构造函数的调用语句,所以我们常说构造函数是在对象声明时由系统自动调用的。&&&&&& 上一讲那个时钟例子中,鸡啄米没有定义Clock类的构造函数,编译器编译时会自动生成一个默认形式的构造函数,这个构造函数不做任何事,那么为什么还要生成它呢?因为C++在对象建立时都会调用构造函数,所以如果没有自己定义构造函数,那么即使是什么都不做的构造函数也是要有的。鸡啄米现在在Clock类中加入自己定义的构造函数:&&&&&& &class Clock&&&&&&& {&&&&&&& public:&&&&&&&&&&&&&&&&& Clock(int NewH, int NewM, int NewS);&&&&&&&&&&&&& //构造函数&&&&&&&&&&&&&&&&& void SetTime(int NewH, int NewM, int NewS);&&&&&&&&&&&&&&&&&&void ShowTime();&&&&&&& private:&&&&&&&&&&&&&&&& &int Hour, Minute, S&&&&&&& };&&&&&&& 构造函数的实现:&&&&&&& Clock::Clock(int NewH, int NewM, int NewS)&&&&&&& {&&&&&&&&&&&&&&&& Hour=NewH;&&&&&&&&&&&&&&&& Minute=NewM;&&&&&&&&&&&&&&&& Second=NewS;&&&&&&& }&&&&&&&&建立对象时构造函数的作用:&&&&&& &int main()&&&&&&& {&&&&&&&&&&&&&&& Clock c(0,0,0); //隐含调用构造函数,将初始值作为实参。&&&&&&&&&&&&&&& c.ShowTime();&&&&&&&&&&&&&&& return 0;&&&&&&& }&&&&&&&main函数中,创建对象c时,其实隐含了构造函数的调用,将初始值0,0,0作为构造函数的实参传入。因为上面Clock类定义了构造函数,那么编译器就不会再为它生成默认构造函数了。这里的构造函数有三个形参,那么建立对象就必须给出初始值了。&&&&&&&因为构造函数也是一个成员函数,所以它可以直接访问类的所有数据成员,可以是内联函数,可以带有形参表,可以带默认的形参值,也可以重载,就是有若干个名字相同但形参个数或者类型不同的构造函数。&&&&&&&2.拷贝构造函数&&&&&& 我们可以将一个变量的值赋给另一个同类型的变量,那么可以将一个对象的内容拷贝给相同类的另一个对象吗?可以,我们可以将第一个对象的数据变量的值分别赋给另一个对象的数据变量,但是,如果数据变量数很多的话那将是很麻烦的,这时候我们就需要有拷贝构造函数。&&&&&&&拷贝构造函数是一种特殊的构造函数,因为它也是用来构造对象的。它具有构造函数的所有特性。拷贝构造函数的作用是用一个已经存在的对象去初始化另一个对象,这两个对象的类类型应该是一样的。定义拷贝构造函数的形式是:&&&&&& class 类名&&&&&&&{ &&&&&& &public :&&&&&&&&&&&&&&&&&& 类名(形参);&&&&&&&&&&&&&&&&&& &//构造函数&&&&&&&&&&&&&&&&&& 类名(类名 &对象名);&& //拷贝构造函数&&&&&&&&&& ...&&&&&&&};&&&&& &类名::类(类名 &对象名)&&& //拷贝构造函数的实现&&&& & {&& &&&&&&&&&&&&&&&& 函数体&&& &&&&& &}&&&&&& 拷贝构造函数的形参是本类的对象的引用。&&&&& &程序中如果没有定义拷贝构造函数系统会生成一个默认的拷贝构造函数,它会将作为初始值的对象的数据成员的值都拷贝到要初始化的对象中。下面鸡啄米给大家一个坐标点类的例子,X和Y数据成员分别为点的横坐标和纵坐标:&&&&&& class Point&&&&&& {&&&&&& public:&&&&&&&&&&&&&&&&&& Point(int xx=0,int yy=0)&&& {X= Y=}&&&&&&&&&&&&&&&&&& Point(Point &p);&&&&&&&&&&&&&&&&& &int GetX() {return X;}&&&&&&&&&&&&&&&&&& int GetY() {return Y;}&&&&&& private:&&&&&&&&&&&&&&&&& &int& X, Y;&&&&& &};&&&&& 此类中声明了内联构造函数和拷贝构造函数。拷贝构造函数的实现如下:&&&&& Point::Point(Point &p)&&&&& {&&&&&&&&&&&&&&&&&&X=p.X;&&&&&&&&&&&&&&&&& Y=p.Y;&&&&&&&&&&&&&&&& &cout&&&拷贝构造函数被调用&&&&&&&& }&&&&& 拷贝构造函数在以下三种情况下会被调用:&&&&& a.当用类的一个对象去初始化该类的另一个对象时系统自动调用拷贝构造函数实现拷贝赋值。&&&&&& int main()&&&&&& {& &&&&&&&&&&&&&&& Point A(1,2);&&&&&&&&&&&&&&& Point B(A); //拷贝构造函数被调用&&&&&&&&&&&&&&& cout&&B.GetX()&&&&&&&&&&&&&&&&& return 0;&&&&&& }&&&&&& b.若函数的形参为类对象,调用函数时,实参赋值给形参,系统自动调用拷贝构造函数。例如:&&&&&& void fun1(Point p)&&&&&& {&& &&&&&&&&&&&&&&& cout&&p.GetX()&&&&&&&& } &&&&&& int main()&&&&&& {&& &&&&&&&&&&&&&& Point A(1,2);&&&&&&&&&&&&&& fun1(A); //调用拷贝构造函数&&&&&&&&&&&&&& return 0;&&&&&& }&&&&&&&&&&& c.当函数的返回值是类对象时,系统自动调用拷贝构造函数。例如:&&&& & Point fun2()&&&&&& {&&& &&&&&&&&&&&&& Point A(1,2);&&&&&&&&&&&&& return A; //调用拷贝构造函数&&&&&& }&&&&&& int main()&&&&&& {&&&&&&&&&&&& Point B;&&&&&&&&&&&& B=fun2();&&&&&&&&&&&& return 0;&&&&&& }&&&&& &最后这种情况怎么调用的拷贝构造函数呢?对象A是局部对象,在fun2函数执行完就释放了,那怎么将它拷贝给对象B呢?编译器在执行B=fun2()时会创建一个临时的无名对象,在执行return A时实际上是调用了拷贝构造函数将A的值拷贝到了临时对象中,A就释放了,然后将临时对象的值再拷贝到对象B中。&&&&&& 3.析构函数&&&&&& 自然万物都是有生有灭的,类的对象也一样是有生命周期的,一样会消亡。鸡啄米给大家讲一种情况:如果在函数中声明了一个对象,那么在这个函数运行完返回调用函数时,声明的对象也会释放,就像上面说的fun2函数中对象A那样。&&&&&&&在对象释放时都有什么工作要做呢?我们经常遇到的情况就是:构造函数时动态申请了一些内存单元,在对象释放时就要同时释放这些内存单元。动态分配内存的知识后面鸡啄米会讲。&&&&&& 析构函数和构造函数的作用是相反的,它会在对象被删除之前做一些清理工作。析构函数是在对象要被删除时由系统自动调用的,它执行完后对象就消失了,分配的内存空间也释放了。&&&&& &析构函数是类的一个公有函数成员,它的名称是在类名前加&~&形成,不能有返回值,大家注意下,它和构造函数不同的是它不能有任何形参。如果没有定义析构函数系统也会自动生成一个默认析构函数,默认析构函数也不会做任何工作。一般如果我们想在对象被删除之前做什么工作就可以把它写到析构函数里。&&&&&& 鸡啄米还是在上面那个坐标点类中加入析构函数给大家看下析构函数怎么用:&&&&&& class Point&&&&&& {&&&& &&&&& &public:&&&&&&&&&&&&&&&&&& Point(int xx, int yy);&&&&&&&&&&&&&&&&& &~Point();&&&&&&&&&&&&&&&&&& //...其他函数原型&&&&&& private:&&&&&&&&&&&&&&&& &int X, int Y;&&&&&&&&&&&&&&&& &char *p;&&&&&& };&&&&&& 下面是构造函数和析构函数的实现:&&&&&& Point::Point(int xx,int yy)&&&&&& {&&&&&&&&&&&&&&&&&&&&&&X=&&&&&&&&&&&&&&&&&&& Y=&&&&&&&&&&&&&&& &p=new char[20];&&&& // 构造函数中动态分配char型内存&&&&&& }&&&&&& Point::~Point()&&&&&& {&&&&&&&&&&&&&&& delete []&&&&& // 在类析构时释放之前动态分配的内存&&&&&& }&&&&&& //...其他函数的实现略&&&&&& new和delete的用法鸡啄米后面会讲,这里只是让大家看下析构函数有什么作用。&&&&& &构造函数和析构函数是大家C++编程入门时必须掌握的内容,很多公司笔试或面试时都会考到,大家掌握好啊,呵呵。鸡啄米谢谢大家关注我的教程!我们一起努力!&
除非特别注明,文章均为原创
转载请标明本文地址:
作者:鸡啄米
&&( 21:4:52)&&( 22:35:5)&&( 23:2:28)&&( 21:37:49)&&( 20:40:25)&&( 20:25:52)&&( 20:51:25)&&( 20:15:8)&&( 21:7:46)&&( 22:17:54)
真够专业 的,我一个也看不懂
会点vb这个还真看着晕乎~嘿嘿以后多来学习!
技术篇,完全看不懂,,就当我打酱油吧。
先拜膜一下,,,,看到这个就有点头晕。。
学习一下。。..太专业了。。
学过一段时间,最后还是决定学JAVA了鸡啄米 于
23:18:51 回复java我也学过,只是没做过多少这方面的东西
写程序太困难。。。
程序,俺不懂!!!
构造函数比较难!
不错哦。。支持一个。。学习了
C++,伤不起啊
彻底蒙了!鸡啄米 于
21:52:58 回复思考思考,消化消化,再回来看就会感觉好些了。
这节看起来有点难了鸡啄米 于
22:28:05 回复本节内容在面向对象编程中很重要,最好理解透彻
Point::~Point(){
// 在类析构时释放之前动态分配的内存}这段代码编译过了,但是执行的时候出错了。我用的是VS2008,最后再dbgdel.cpp文件中的“void operator delete(void *pUserData)&函数中断言了。
/* verify block type */
ASSERTE(_BLOCK_TYPE_IS_VALID(pHead-&nBlockUse));这个,怎么回事呢?000000 于
01:02:32 回复Point::~Point(){delete [] // 在类析构时释放之前动态分配的内存}应该是 delete []p;
楼主快修改下文章
19:40:44 回复应该是 &delete []p&.......这边文章写的很细,赞!起码读2遍。
能不能讲点MFC如何调用matlab,并实现混编,matlab的函数里包含vc的变量,博主这么厉害应该也精通这个吧,求指教,求写出来,像MFC那个做成教程挺好的,强烈建议
Point fun2()
Point A(1,2);
return A; //调用拷贝构造函数
int main()
}求教!这段代码是不是存在bug?Point A(1,2)说明有自己编写的构造函数,所以下面的Point B也必须给对象B附初值,否则会提示 no matching function for call
完全随机文章

我要回帖

更多关于 构造函数与析构函数 的文章

 

随机推荐