C++对象的创建与销毁

构造函数

  • 构造函数能在创建对象时被调用,用于初始化成员。
  • 构造函数的名字与类的名字相同,没有返回值(不是void,是没有
  • 构造函数可以重载,通过设置不同参数列表和默认值,可以用不同方式初始化。
  • 在没有定义任何构造函数时,编译器会自动生成默认构造函数,但是一旦定义了构造函数,系统就不会再生成默认构造函数。
  • 成员初始化列表
    • 类中引用成员、const数据成员、类类型数据成员不能用赋值的方式初始化。这对这一种情况,有一种特殊语法,即初始化列表。
    • 初始化列表位于构造函数参数表之后,函数体之前,即:
      构造函数(参数表):初始化列表 { 函数体 }
    • 初始化列表的格式:
      成员1(初始值1),成员2(初始值2),…
    • 普通成员也可以用这种方式进行初始化。
class X{
	int m;
	int& r;
public:
	X(int v = 0) : r(m) {
		m = v;
	}
};
class X{
	int m;
	int& r;
public:
	X(int v = 0) : m(v), r(m) { }
};
  • 类型转换构造函数
    • 带一个参数的构造函数也被看做是进行类型转换的函数,它可以将参数类型的数据转换为类类型。
    • 在需要隐式类型转换时编译器会自动调用转换构造函数。
class X{
	int m;
public:
	X(int v): m(v){ } //转换构造函数,可以将int转换为X类型
};
void f(X obj) { }
int main()
{
	int iv = 10;
	f(iv);   //OK,调用X(int)进行隐含的参数类型转换
	return 0;
}
class X{
	int m;
public:
	explicit X(int v): m(v){ } 
	// 说明这是普通的构造函数,不能在需要类型转换时调用
};
  • 拷贝构造函数
    • 在用已有对象去初始化另一个同类型的对象时,需要用到拷贝构造函数。
    • 拷贝构造函数的参数列表是X&,如果没有定义这样的参数列表,编译器会自动给出一个浅拷贝构造函数。如果类中包含指针和引用成员,浅拷贝有逻辑错误,要自己定义拷贝函数。
#include <iostream>
using namespace std;
class X{
	int m;
	int& r;
	int* p;
public:
	X(int mm = 0): m(mm), r(m), p(&m) { }
	void changep(){ *p = 10; }
	void changer(){ r = 5; }
	int getm(){ return m; }
};

int main()
{
	X a;
	X b(a);
	cout<<a.getm()<<endl;
	b.changep();
	cout<<a.getm()<<endl;
	b.changer();
	cout<<a.getm()<<endl;
	return 0;
}

在这里插入图片描述

错误原因就是浅拷贝函数把b的 r 和 p 都赋成了a中m的地址。
我们这时要自己定义一个构造函数
X(X& a): m(a.m), r(m), p(&m) { }

在这里插入图片描述

拷贝构造函数在如下情况下会被调用
void f(X obj) { }
X g(){
    Y obj;
    return obj;
}
int main()
{
    Y a;
    Y b = a; //等价于b(a),调用
    f(a);    //参数按值传递,调用
    b = g(); //参数按值返回,调用
 }
后两种情况都是按值返回时才调用,引用传递和返回时不会调用。

析构函数

  • 析构函数在对象生命周期结束时或用delete释放时,析构函数会自动被调用。
  • 析构函数的名字是类名字前加波浪线~
  • 析构函数和构造函数一样,没有返回值类型。
  • 析构函数不能重载,只能定义唯一一个析构函数。

实例

设计一个平面线类,要求
  • 线有两个点确定
  • 点由其横坐标和纵坐标确定
  • 可以通过改变点的坐标改变线段位置
  • 可以得到线段长度
  • 不可以使用友元
#include <iostream>
#include <cmath>
using namespace std;
class Point{
	double x,y;
public:
	Point(double x = 0, double y = 0){
		this -> x = x;
		this -> y = y;
	}
	void setx(double xx){ x = xx;}
	void sety(double yy){ y = yy;}
	double getx(){ return x;}
	double gety(){ return y;}
	void getPoint(){
		cout<<'('<<x<<','<<y<<')';
	}
};
class Line{
	Point a,b;
public:
	Line(Point aa,Point bb): a(aa), b(bb) { }
	void changePointStart(double xx,double yy){
		a.setx(xx); a.sety(yy);
	}
	void changePointEnd(double xx,double yy){
		b.setx(xx); b.sety(yy);
	}
	void getLine(){
		cout<<"直线由"; a.getPoint();b.getPoint();
		cout<<"组成,长度为"<<getLong()<<endl;
	}
	double getLong(){
		double detax,detay;
		detax = a.getx() - b.getx(); detay = a.gety() - b.gety();
		return sqrt(detax * detax + detay * detay);
	}
};

int main()
{
	Point a,b(3,4);
	Point c = b;
	cout<<"初始值为a"; a.getPoint();cout<<",b"; b.getPoint();
	cout<<",c"; c.getPoint(); cout<<endl;
	Line l1(a,b);
	l1.getLine();
	Line l2 = l1;
	l2.changePointStart(8,10);
	l2.getLine();
	return 0;
}

在这里插入图片描述

猜你喜欢

转载自blog.csdn.net/qq_43575267/article/details/86754192