C++学习笔记1:构造函数和析构函数
来源:互联网 发布:编写js的工具 编辑:程序博客网 时间:2024/05/17 04:03
在C++语言中,构造函数主要起初始化对象的作用。当一个对象的生命周期结束时,我们应该去释放这个对象
所占用的资源,这可以利用析构函数来完成。下面我们以几个具体的例子来深入讲解C++的构造函数和析构函数。
1 构造函数
#include <iostream.h>
class point
{
int x;
int y;
public:
point() //构造函数
{
x=0;
y=0;
}
void output()
{
cout<<x<<endl<<y<<endl;
}
};
void main()
{
point pt;
pt.output();
}
运行结果:
0
0
分析:
(1) 构造函数与类同名
(2) 构造函数的作用是对对象本身做初始化工作,也就是给用户提供初始化类中成员变量的一种方式
(3) 如果一个类中没有定义任何一的构造函数,那么C++编译器在某些情况下会为该类提供一个默认的构造函数,这个默认的构造函数是一个不带参数的构造函数。只要一个类中定义了一个构造函数,不管这个构造函数是否是带参数的构造函数,C++编译器就不再提供默认的构造函数。也就是说,如果为一个类定义了一个带参数的构造函数,还想要无参数的构造函数。
2 析构函数
class Student
{
private:
char *pName;
public:
Student() //构造函数
{
pName=New char[20];
}
~Student() //析构函数
{
delete[] pName;
}
};
析构函数不允许带参数,并且一个类中只能有一个析构函数。
3 Point类的拷贝构造函数
#include<iostream>
using namespace std;
class Point
{
public:
Point(int xx=0,int yy=0){X=xx,Y=yy;} //构造函数
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<<"拷贝构造函数被调用"<<endl;
}
void fun1(Point p) //形参为Point类的函数
{
cout<<p.GetX()<<endl;
}
Point fun2() //返回值为Point类对象的函数
{
Point A(1,2);
return A;
}
int main()
{
Point A(4,5);
Point B(A); //情况一,用A初始化B。调用拷贝构造函数
cout<<B.GetX()<<endl;
fun1(B); //情况二,对象B作形参。调用拷贝构造函数
B=fun2(); //情况三,返回值是类对象,函数返回时,调用拷贝构造函数
cout<<B.GetX()<<endl;
}
运行结果:
拷贝构造函数被调用
4
拷贝构造函数被调用
4
拷贝构造函数被调用
1
4 类的组合,Line
源程序:
#include<iostream>
#include<cmath>
using namespace std;
class Point
{
public:
Point(int xx=0,int yy=0){X=xx;Y=yy;}
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<<"Point拷贝构造函数被调用"<<endl;
}
//类的组合
class Line
{
public:
Line(Point xp1,Point xp2); //构造函数
Line(Line &);
double GetLen() {return len;}
private:
Point p1,p2;
double len;
};
//组合类的构造函数的实现
Line::Line(Point xp1,Point xp2):p1(xp1),p2(xp2)
{
cout<<"Line构造函数被调用"<<endl;
double x=double(p1.GetX()-p2.GetX());
double y=double(p1.GetY()-p2.GetY());
len=sqrt(x*x+y*y);
}
//组合类的拷贝构造函数
Line::Line(Line &L):p1(L.p1),p2(L.p2)
{
cout<<"Line拷贝构造函数被调用"<<endl;
len=L.len;
}
void main()
{
Point myp1(1,1),myp2(4,5); //建立Point类的对象
Line line(myp1,myp2); //建立Line类的对象
Line line2(line); //对上一步进行拷贝并建立新对象
cout<<"The length of the line is:";
cout<<line.GetLen()<<endl;
cout<<"The length of the line2 is:";
cout<<line2.GetLen()<<endl;
}
运行结果:
Point拷贝构造函数被调用
Point拷贝构造函数被调用
Point拷贝构造函数被调用
Point拷贝构造函数被调用
Line拷贝构造函数被调用
Point拷贝构造函数被调用
Point拷贝构造函数被调用
Line拷贝构造函数被调用
The length of the line is:5
The length of the line2 is:5
5 对象数组
源程序:
//Point.h
#if!defined(_POINT_H)
#define _POINT_H
class Point
{
public:
Point();
Point(int xx,int yy);
~Point();
void Move(int x,int y);
int GetX() {return X;}
int GetY() {return Y;}
private:
int X,Y;
};
#endif
//Point.cpp
#include<iostream>
#include"Point.h"
using namespace std;
Point::Point()
{
X=Y=0;
cout<<"Default Constructor called."<<endl;
}
Point::Point(int xx,int yy)
{
X=xx;
Y=yy;
cout<<"Constructor called."<<endl;
}
Point::~Point()
{
cout<<"Destructor called."<<endl;
}
void Point::Move(int x,int y)
{
X=x;
Y=y;
}
//6_3.cpp
#include<iostream>
#include"Point.h"
using namespace std;
int main()
{
cout<<"Entering main..."<<endl;
Point A[2];
for(int i=0;i<2;i++)
A[i].Move(i+10,i+20);
cout<<"Exiting main..."<<endl;
}
运行结果:
Entering main…
Default Constructor called.
Default Constructor called.
Exiting main…
Destructor called.
Destructor called.
6 函数调用
源程序:
#include<iostream.h>
class B
{
int x,y;
public:
B() {x=y=0;cout<<"Constructor1"<<endl;}
B(int i) {x=i;y=0;cout<<"Constructor2"<<endl;}
B(int i,int j) {x=i;y=j;cout<<"Constructor3"<<endl;}
~B() {cout<<"Destructor"<<endl;}
void printf()
{
cout<<"x="<<x<<",y="<<y<<endl;
}
};
void main()
{
B *ptr;
ptr=new B[3];
ptr[0]=B();
ptr[1]=B(5);
ptr[2]=B(2,3);
for(int i=0;i<3;i++)
ptr[i].printf();
delete[] ptr;
}
运行结果:
Constructor1
Constructor1
Constructor1
Constructor1
Destructor
Constructor2
Destructor
Constructor3
Destructor
x=0,y=0
x=5,y=0
x=2,y=3
Destructor
Destructor
Destructor
分析:
执行ptr=new B[3];调用第一个构造函数3次;
执行ptr[0]=B();创建一个无名对象,等价于{B temp; ptr[0]=temp; 释放temp},因此调用第一个构造函数1次,调用析构函数1次;
执行ptr[1]=B(5);创建一个无名对象,调用第二个构造函数1次,调用析构函数1次;
执行ptr[2]=B(2,3);创建一个无名对象,调用第三个构造函数1次,调用析构函数1次;
执行for循环语句输出相关内容;
最后执行delete[] ptr;删除对象数组ptr,调用析构函数3次。
7 派生类构造函数举例
#include<iostream>
using namespace std;
class B1
{
public:
B1(int i) {cout<<"constructing B1 "<<i<<endl;}
};
class B2
{
public:
B2(int j) {cout<<"constructing B2 "<<j<<endl;}
};
class B3
{
public:
B3() {cout<<"constructing B3 *"<<endl;}
};
class C:public B2,public B1,public B3
{
public:
C(int a,int b,int c,int d):B1(a),memberB2(d),memberB1(c),B2(b){}
private:
B1 memberB1; //B1为类名,memberB1为对象
B2 memberB2;
B3 memberB3;
};
int main()
{
C obj(1,2,3,4);
}
运行结果:
constructing B2 2
constructing B1 1
constructing B3 *
constructing B1 3
constructing B2 4
constructing B3 *
分析:
基类构造函数的调用顺序是按照派生类声明时的顺序,先B2再B1再B3
内嵌对象的构造函数调用顺序是按照成员在类中声明的顺序,先B1再B2再B3
8 没有使用虚析构函数
源程序:
#include<iostream>
using namespace std;
class Base
{
public:
~Base() {cout<<"Base destructor/n";}
};
class Derived:public Base
{
public:
Derived();
~Derived();
private:
int *i_pointer;
};
Derived::Derived()
{i_pointer=new int(0);}
Derived::~Derived()
{
cout<<"Derived destructor/n";
delete i_pointer;
}
void fun(Base *b)
{delete b;}
int main()
{
Base *b=new Derived();
fun(b);
}
运行结果:
Base destructor
分析:
通过基类指针删除派生类对象时调用的是基类的析构函数,派生类的析构函数没有被执行,因此派生类对象中动态分配的内存空间没有得到释放,造成了内存泄漏。也就是说派生类对象成员i_pointer所指向的内存空间,在对象消失后既不能被本程序继续使用也没有被释放。对于内存需求量较大、长期连续运行的程序来说,如果持续发生这样的错误是很危险的,最终将导致因内存不足而引起程序的终止。
9 使用虚析构函数
源程序:
#include<iostream>
using namespace std;
class Base
{
public:
virtual ~Base() {cout<<"Base destructor/n";}
};
class Derived:public Base
{
public:
Derived();
~Derived();
private:
int *i_pointer;
};
Derived::Derived()
{i_pointer=new int(0);}
Derived::~Derived()
{
cout<<"Derived destructor/n";
delete i_pointer;
}
void fun(Base *b)
{delete b;}
int main()
{
Base *b=new Derived();
fun(b);
}
运行结果:
Derived destructor
Base destructor
分析:
这说明派生类的析构函数被调用了,派生类对象中动态申请的内存空间被正确地释放了。这是由于使用了虚析构函数,实现了多态。
- C++学习笔记1:构造函数和析构函数
- C/C++学习笔记:String类的构造函数、析构函数和赋值函数
- Objective-C学习笔记---构造函数和析构函数
- Objective-C学习笔记---构造函数和析构函数
- 【C++】学习笔记四十七——类的构造函数和析构函数
- 学习C++——构造函数和析构函数
- c#学习笔记-构造函数和析构函数
- C#学习笔记9-构造函数和析构函数
- c++学习笔记之构造函数和析构函数
- c++学习笔记(十二):构造函数和析构函数
- 构造函数和析构函数【c++】
- [c++]构造函数和析构函数
- 【C#】构造函数和析构函数
- 【C++】构造函数和析构函数
- 【C++】构造函数和析构函数
- C++:构造函数和析构函数
- C++ 析构函数与构造函数 学习笔记1
- C++学习笔记-----不要在构造函数和析构函数中调用虚函数
- Win32 API 函数大全使用详解十 鼠标输入函数
- c# windowsmobile开发技巧
- EGL Configurations
- gdjlc解答:前台函数调用及正则表达式问题
- bboss taglib 分页/列表标签功能介绍
- C++学习笔记1:构造函数和析构函数
- const的使用
- 2009.06.18 20:00天体15号球场连中六个三分,四个NBA三分,要多锻炼!
- 以原始套接字的方式 截获流经本机网卡的IP数据包(转)
- 安装Google App Engine for Java开发工具集
- explicit 修饰符
- FLEX 笔记--组件的行为和动画效果
- 抛开cookie使用session-PHP中SESSION不能跨页传递问题的解决办法
- 软件的可维护性和可复用性