C++面向对象--第二章类与对象

构造函数

是一种特殊的成员函数,主要功能是为对象分配存储空间,以及为类成员变量赋初值

可以重载

构造函数名必须与类名相同

没有任何返回值和返回类型

创建对象自动调用,不需要用户来调用,且只调用一次

类没有定义任何构造函数,编译系统会自动为这个类生成一个默认的无参构造函数

构造函数定义

1.类中定义

2.类中声明类外定义

        

构造函数的调用

1.显式调用

        显式调用有参构造:Data ob=Data(20);

        显式调用无参构造:Data ob=Date();

2.隐式调用

        隐式调用有参构造:Data ob(20);

        隐式调用无参构造:Data ob;

3.隐式转换的方式调用有参构造(针对只有一个数据成员)【尽量别用】

        Data ob=30;-----Data ob(30);

4.匿名对象

        Data(4);//当前语句结束,匿名对象立即释放

5.指针调用

        类名 *指针变量名=new 类名(实参列表)---Score *stu=new Score(99,100);

默认参数的构造函数

初始化列表的构造函数

成员初始化列表:类名::构造函数名(参数) : (成员初始化列表) { }

初始化成员变量,除了使用构造函数初始化外,还可以用成员初始化列表

特别:当类的对象作为另一个类的成员时,可以显示调用对象成员的构造函数

顺序:对象成员的构造函数---自己的构造函数---析构自己---析构对象成员

注意:类成员是按照它们在类里被声明的顺序进行初始化的,与它们在成员初始化列表中列出的顺序无关。

构造函数重载

构造函数名字相同,参数个数和参数类型不一样。

析构函数

是一种特殊的成员函数,当对象的生命周期结束时,用来释放分配给对象的内存空间,并做一些清理的工作。

不能重载

析构函数名与类名必须相同,并且析构函数名前面必须加一个波浪号~

没有参数,没有返回值,。

一个类中只能有一个析构函数。

没有定义析构函数,编译系统会自动为和这个类生成一个默认的析构函数。

析构函数的定义

1.类中定义

2.类中声明类外定义

        

必须使用初始化列表的四种情况

1.类成员为const类型

常量成员,因为常量只能初始化不能赋值,所以必须放在初始化列表里面。

2.类成员为引用类型

引用类型,必须在定义的时候初始化,并且不能重新赋值,所以也要写在初始化列表里面

3.如果类存在继承关系,派生类必须在其初始化列表中调用基类的构造函数

拷贝构造函数

是一种特殊的构造函数。其形参是本类对象的常引用

函数名和类名相同,并且也没有返回值

同类对象都有一个拷贝构造函数

拷贝函数只有一个参数---同类对象的引用,为什么是引用类型?

        如果拷贝构造函数使用值传递会发生什么?

                如果使用的值传递,那么在形参与实参相结合时,又要调用本类的拷贝构造函数,导致进入死循环

                如果使用引用传递(const 引用)来调用拷贝构造函数,则只会传递对象的引用,而不会创建新的副本

拷贝构造函数的定义

1.类中定义

2.类中声明类外定义

        

调用拷贝构造函数的三种情况

1.旧对象初始化新对象,会调用拷贝构造函数

class Baz 
{
public:
    int value;
			
    // 拷贝构造函数
    Baz(const Baz &other) : value(other.value) {}
			
    // 构造函数
    Baz(int val = 0) : value(val) {}
};
			
int main() 
{
    Baz baz1(42);
    Baz baz2 = baz1; // 触发拷贝构造函数的调用
    return 0;
}

2.当函数的形参是类的对象,调用函数进行形参和实参结合时,会调用拷贝构造函数

class Foo 
{
public:
	int value;

	// 拷贝构造函数
	Foo(const Foo &other) : value(other.value) {}

	// 构造函数
	Foo(int val = 0) : value(val) {}
};

void someFunction(Foo foo) {
	// ...
}

int main() 
{
	Foo foo(42);
	someFunction(foo); // 触发拷贝构造函数的调用
	return 0;
}

3.当函数的返回值是对象,函数执行完成返回调用者时,会调用拷贝构造函数

class Bar 
{
public:
	int value;

	// 拷贝构造函数
	Bar(const Bar &other) : value(other.value) {}

	// 构造函数
	Bar(int val = 0) : value(val) {}
};

Bar someFunction() {
	Bar bar(42);
	return bar; // 触发拷贝构造函数的调用
}

int main() 
{
	Bar bar2 = someFunction();
	return 0;
}

区别:

        

自定义拷贝构造函数

原因:深拷贝和浅拷贝

浅拷贝:由默认的拷贝构造函数所实现的数据成员逐一赋值。大多数情况下默认构造函数是可以胜任这项工作的,但如果类中存在指针类型的数据,浅拷贝就会发生错误。

        

        上述错误是因为stu1和stu2所指的内存空间相同,在析构函数释放stu1所指的内存后,再释放stu2所指的内存会发生错误,因为此内存空间已被释放。解决方法就是重定义拷贝构造函数,为其变量重新生成内存空间。

默认构造函数的调用规则

系统会给任何一个类提供3个成员函数:默认构造函数,默认析构函数,默认拷贝函数

1.如果用户提供了有参构造,将屏蔽系统的默认构造函数

//可行
class A
{
private:
	        int a;
public:
	        
};

int main()
{
	        A x;
	        return 0;
}

//报错
class A
{
private:
	        int a;
public:
	        A(int t):a(t){}
};

int main()
{
	        A x;
	        return 0;
}

2.如果用户提供了有参构造不会屏蔽系统的默认拷贝构造函数

class A
{
private:
	        int a;
public:
	        A(int t):a(t){}
	        int Geta(){        return a;        }
};

int main()
{
	        A x1(10);
	        A x2=x1;
	        cout<<x2.Geta();//输出10
	        return 0;
}

3.如果用户提供了拷贝构造函数,将屏蔽系统的默认构造函数、默认拷贝构造函数

class A
{
private:
		int a;
public:
		A(const A &b){        a=b.a;        };//拷贝构造函数中可以访问到private和protected
		int Geta(){        return a;        }
};

int main()
{
		A x;//报错
		return 0;
}

注意:普通类外函数在引用一个类的实例时,无法访问其privateprotected。但是该类的拷贝构造函数可以访问到其privateprotected

总结:对于一个类,用户一般要实现:无参构造(初始化)、有参构造(赋值)、拷贝构造(深拷贝)、析构(释放空间)。 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值