C++(构造函数和创建类对象)

news/2024/11/20 10:43:17/文章来源:https://www.cnblogs.com/hGG-SK/p/18556364

一)构造函数的概念
构造函数是一种特殊的成员函数,用于在创建对象时初始化对象的数据成员。它的主要目的是确保对象在使用前被正确地初始化,使得对象处于一个合理的初始状态。构造函数的名称与类名相同,没有返回类型(包括void)。例如,对于一个名为MyClass的类,其构造函数可以写成MyClass()或者MyClass(int parameter)等形式。
二)默认构造函数的定义和特点
定义:
默认构造函数是一种可以在没有显式提供初始化值的情况下调用的构造函数。它有两种形式:一种是编译器自动生成的默认构造函数,另一种是用户自己定义的默认构造函数(无参数构造函数或者所有参数都有默认值的构造函数)。
编译器自动生成的默认构造函数:
当类中没有定义任何构造函数时,编译器会自动为该类生成一个默认构造函数。这个默认构造函数会对类的基本数据类型成员进行默认初始化。对于基本数据类型的成员变量,在不同的存储类别下初始化行为有所不同。例如,在全局或静态存储区域的对象,基本数据类型的成员变量会被初始化为 0;而对于自动存储区域(如函数内部定义的局部对象)的基本数据类型成员变量,它们的值是未定义的(缺点)
例如,对于以下类:

class MyClass 
{
public:int num;double value;
};

如果创建一个全局对象MyClass globalObj;,那么globalObj.num会被初始化为 0,globalObj.value也会被初始化为 0。但如果在函数内部创建一个局部对象MyClass localObj;,localObj.num和localObj.value的值是未定义的。
用户自定义的默认构造函数:
用户可以自己定义默认构造函数来满足特定的初始化需求。用户自定义的默认构造函数有两种情况:一是无参数的构造函数,二是所有参数都有默认值的构造函数。
例如,无参数的默认构造函数:

class MyClassWithCustomConstructor 
{
private:int num;
public:MyClassWithCustomConstructor() {num = 0;}
};

在这个例子中,当创建MyClassWithCustomConstructor对象时,如MyClassWithCustomConstructor obj;,对象的num成员会被初始化为 0。
所有参数都有默认值的构造函数示例:

class AnotherClass 
{
private:int num;double value;
public:AnotherClass(int n = 0, double v = 0.0){num = n;value = v;}
};

对于AnotherClass,可以通过AnotherClass obj;(此时num为 0,value为 0.0)或者AnotherClass obj(5);(此时num为 5,value为 0.0)等方式来创建对象,并且对象会根据提供的参数或者默认值进行初始化。
初始化列表方式的默认构造函数(推荐用于成员变量初始化)
语法和示例:
初始化列表是在构造函数的参数列表后面紧跟一个冒号(:),然后是成员变量初始化列表,每个成员变量用逗号隔开。
例如,对于Person类,使用初始化列表的默认构造函数可以这样写:

class Person 
{
private:std::string name;int age;
public:Person() : name("Unknown"), age(0) {}
};

这种方式直接在构造函数开头就对成员变量进行初始化,对于一些特殊类型的成员变量(如const成员变量、引用成员变量),必须使用初始化列表进行初始化。而且,使用初始化列表通常效率更高,因为它是在对象创建时直接初始化成员变量,而不是先默认初始化成员变量,再在构造函数体中进行赋值操作。
三)创建类对象的几种方式
1)使用默认构造函数创建对象
无参数的默认构造函数方式
定义和特点:当类定义了一个无参数的默认构造函数时,可以直接使用类名加空括号来创建对象。这种方式简单直接,适用于对象的初始化逻辑相对固定,不需要外部传入参数来改变初始状态的情况。

class Circle 
{
private:double radius;
public:Circle(){radius = 1.0;}double getRadius() {return radius;}
};
int main() 
{Circle c;std::cout << "Radius of the circle: " << c.getRadius() << std::endl;return 0;
}

在这个例子中,Circle类有一个无参数的默认构造函数,在构造函数中radius被初始化为 1.0。在main函数中,通过Circle c;创建了一个Circle对象,然后可以使用对象的成员函数getRadius来获取半径的值。
所有参数都有默认值的构造函数方式(也可视为默认构造函数)
定义和特点:这种构造函数带有参数,但每个参数都有默认值。它既可以像无参数的默认构造函数那样,在不传入任何参数时使用默认值进行初始化,也可以根据需要传入部分或全部参数来覆盖默认值进行初始化。这种方式提供了更大的灵活性,使得对象的初始化可以根据不同的场景进行调整。

class Rectangle 
{
private:int width;int height;
public:Rectangle(int w = 2, int h = 3) {width = w;height = h;}int getArea() {return width * height;}
};
int main() 
{// 使用默认值创建对象Rectangle r1;// 传入部分参数创建对象Rectangle r2(4);// 传入全部参数创建对象Rectangle r3(5, 6);std::cout << "Area of r1: " << r1.getArea() << std::endl;std::cout << "Area of r2: " << r2.getArea() << std::endl;std::cout << "Area of r3: " << r3.getArea() << std::endl;return 0;
}

这里Rectangle类的构造函数有两个参数,每个参数都有默认值。在main函数中,通过不同的方式创建了三个Rectangle对象,展示了这种构造函数的灵活性。
2)使用带参数的构造函数创建对象(是所有参数都有默认值的构造函数方式的简化版本)
定义和特点:当类的构造函数带有参数时,需要在创建对象时传入相应的参数,这些参数用于初始化对象的成员变量。这种方式可以根据具体的参数值来创建具有不同初始状态的对象,使得对象的创建更加灵活,能够满足各种不同的需求。

class Point 
{
private:int x;int y;
public:Point(int a, int b) {x = a;y = b;}void print() {std::cout << "Point(" << x << ", " << y << ")" << std::endl;}
};
int main() 
{Point p(3, 4);p.print();return 0;
}

在这个Point类中,构造函数接受两个参数,用于初始化x和y成员变量。在main函数中,通过Point p(3, 4);创建了一个Point对象,其中x被初始化为 3,y被初始化为 4,然后可以使用print函数来输出点的坐标。
3)使用拷贝构造函数创建对象(浅拷贝和深拷贝)
浅拷贝定义和示例:
定义:拷贝构造函数是一种特殊的构造函数,用于使用一个已存在的同类型对象来初始化新创建的对象。浅拷贝是指在拷贝对象时,对于对象中的指针或引用类型的成员,只是简单地复制指针或引用的值,而不是复制它们所指向或引用的内容。

class ShallowCopyExample 
{
private:int* data;
public:ShallowCopyExample(int d) {data = new int(d);}ShallowCopyExample(const ShallowCopyExample& other) {data = other.data;}~ShallowCopyExample() {delete data;}
};
int main() 
{ShallowCopyExample obj1(5);ShallowCopyExample obj2 = obj1;return 0;
}

在这个例子中,ShallowCopyExample类有一个指针成员data。拷贝构造函数进行了浅拷贝,只是复制了指针的值。当对象被销毁时,会出现问题,因为obj1和obj2的data指针指向同一块内存,两次调用delete会导致错误。
深拷贝定义和示例:
定义:深拷贝是指在拷贝对象时,对于对象中的指针或引用类型的成员,会复制它们所指向或引用的内容,而不是仅仅复制指针或引用的值。这样可以避免多个对象共享同一块内存导致的问题。

class DeepCopyExample 
{
private:int* data;
public:DeepCopyExample(int d) {data = new int(d);}DeepCopyExample(const DeepCopyExample& other) {data = new int(*other.data);}~DeepCopyExample() {delete data;}
};
int main() 
{DeepCopyExample obj1(5);DeepCopyExample obj2 = obj1;return 0;
}

这里的拷贝构造函数进行了深拷贝,obj2的data指针指向了一块新的内存,这块内存中的内容是从obj1的data所指向的内存中复制过来的。这样在对象销毁时,就不会出现前面浅拷贝的问题。
4)使用动态内存分配创建对象(通过new操作符)
定义和特点:使用new操作符可以在堆上动态地分配内存来创建对象。这种方式创建的对象在内存中的生命周期可以由程序员控制,不会像在栈上创建的对象那样,在离开作用域时自动销毁。这对于需要在一个函数中创建对象,但又希望对象在函数结束后仍然存在的情况非常有用。

class DynamicObject 
{
private:int value;
public:DynamicObject(int v) {value = v;}int getValue() {return value;}
};
int main() 
{DynamicObject* ptr = new DynamicObject(7);std::cout << "Value of the object: " << ptr->getValue() << std::endl;delete ptr;return 0;
}

在这个例子中,通过new操作符创建了一个DynamicObject类的对象,并将对象的指针存储在ptr中。可以通过指针来访问对象的成员函数。最后,使用delete操作符来释放对象占用的内存。
如果你看到这里有点迷惑,这就对了,学习应该是越学越迷惑,如果一学就明白,说明你没有学到知识。后面您还会遇到匿名对象,总之,好像一下子记住好多东西很难,那么就不用强迫自己去记忆,多看、多理解,然后不知不觉就懂了。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.hqwc.cn/news/837233.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

LeetCode 2455[可被三整除的偶数平均值]

LeetCode 2455[可被三整除的偶数平均值]题目 链接 LeetCode 2455[可被三整除的偶数平均值] 详情实例提示题解 思路 遍历容器,for 循环遍历,vector 的 at 方法取元素值 判断能否被3整除,不能则继续遍历 能被3整除则判断能否被2整除,即判断奇偶性,不能被2整除,即为奇数则继…

Microsoft.Extensions.AI 初探

本文介绍了Microsoft.Extensions.AI的基本使用。.NET Conf上的介绍 在今年的.NET Conf上Steve Sanderson带来了题为“AI Building Blocks - A new, unified AI layer”的演讲。该演讲的主要内容如下: “大多数.NET应用程序可以通过AI功能变得更加强大和高效,例如语义搜索、自…

如何确定合适的绩效考核周期和频率?

绩效考核周期的确定需要根据企业的实际情况、不同岗位的特殊性、考核指标的性质及考核标准的不同进行综合考虑。 1、一般来说,管理层级越高的岗位,其考核周期也应该设置得相对较长 2、绩效考核周期过短会增加企业的管理成本;过长又会降低绩效考核数据的准确性比如,销售人员…

什么是OA办公系统?为什么OA办公系统对于企业的作用越来越重要?

如何提升工作效率、优化资源配置、加强团队协作能力,成为了每个企业管理者亟需解决的关键问题。随着企业规模的扩展和业务流程的复杂化,传统的手工操作和纸质文件已经无法满足高效办公的需求。 OA(Office Automation)办公系统应运而生,成为了现代企业提高工作效率、优化管…

关于湖北移动机顶盒CM311-1S长虹版本刷机的总结

最近家里的机顶盒不好使了,就捣鼓了一下自己刷机, 机顶盒是湖北移动的CM311-1s,长虹代工的,晶晨的S905L3处理器,2+8G的配置,用着也还行 这个版本的刷机需要拆机顶盒,找内部的短接点,就是背面这个“4R12”的电阻, 刷机需要用到USB双A头线,接靠近后排插座的那个口,插…

从零搭建UVM验证平台 简介

搭建UVM流程:定义interface。Interface是连接DUT和验证平台的桥梁,根据DUT的输入输出参数定义interface,在top_tb里连接interface和DUT。加入transaction。transaction是一个数据包,transaction由sequence产生,通过sequencer传递给driver。加入driver。Driver负责将接收到…

智慧城市时空基础设施建设与应用实践

智慧城市作为现代城市发展的新趋势,其核心在于利用先进的信息技术,实现城市运行的高效、智能和绿色。时空基础设施作为智慧城市建设的基石,为城市的智慧化提供了基础支撑。本文将探讨智慧城市时空基础设施的建设与应用实践。1. 时空基础设施的重要性时空基础设施是智慧城市不…

echarts 使用移表盘实现类似类目轴效果,不使用数值刻度

思路:使用多个移表盘叠加 效果图:代码: setGaugeChart() {this.gaugeChart && this.gaugeChart?.dispose && this.gaugeChart?.dispose()this.gaugeChart = echarts.init(this.$refs.gaugeChartRef)const grades = [AAA, AA, A, BBB, BB, B, CCC, CC, C, …

Chrome 浏览器 131 版本新特性

Chrome 浏览器 131 版本新特性 一、Chrome 浏览器 131 版本新特性 1. 在 iOS 上使用 Google Lens 搜索 自 Chrome 126 版本以来,用户可以通过 Google Lens 搜索屏幕上看到的任何图片或文字。 要使用此功能,请访问网站,并点击聚焦时出现在地址栏的 Google Lens 搜索按钮,或者…

Qt 重写paintEvent事件划线

可以自定义一个类QtImageLabel继承于QLabel,重写paintEvent事件划线,写文字等。如果用 ui 设计,将 QLabel 控件提升为 QtImageLabel 类型即可。QtImageLabel.h protected:void paintEvent(QPaintEvent *) override;QtImageLabel.cpp #pragma execution_character_set("…

递归定义

GNU “GNU”是“GNUs Not Unix!”(GNU并非Unix!)的首字母递归缩写。 平衡二叉树 也叫AVL树,它或者是一颗空树,或者具有以下性质的二叉排序树:它的左子树和左子树的高度之差(平衡因子)的绝对值不超过1,且它的左子树和右子树都是一颗平衡二叉树。 前序遍历 (preorder tra…

【GreatSQL优化器-03】查询开销估算

【GreatSQL优化器-03】查询开销估算 一、cost和read_time介绍 GreatSQL的优化器在创建执行计划的时候是根据每张表的行数和数据分布以及读数据硬盘消耗等信息来判断先查询哪张表后查询哪张表,要不要使用索引,这些表资源信息就被称为cost,俗称为"开销"。在这之前已…