C++类和对象入门(二)
- 其他
- 2025-09-17 22:30:01

目录
目录
一、类的默认成员函数
二.构造函数
2.1函数名与类名相同
2.2构造函数无返回值
2.3 对象实例化时系统会自动调用
2.4支持函数重载
2.5默认构造函数
2.6无参构造函数与全缺省构造函数与默认构造函数
三、析构函数
3.1析构函数名称
3.2无参数和返回值
3.3一个类只能有一个析构函数
3.4自动调用
3.5显式写析构函数
3.6可以不写的情况
3.7析构函数执行的顺序
四、拷贝构造函数
4.1定义
4.2本质
4.3第一个参数
4.4自定义类型对象的拷贝
4.5若没有显式地写,编译器会自动生成
4.6拷贝函数的传值返回
结语
前言,本文所介绍的知识建立在上文:《C++类和对象入门》
下面我们来继续介绍C++类和对象的进一步讲解和介绍。
一、类的默认成员函数在C++中存在默认成员函数,默认成员函数是指在用户没有显写函数的时候,编译器在C++中会自动生成的函数,一般会有六个函数默认生成,如下图,理解这些函数的行为和作用是理解C++类机制的基础。
本文将详细介绍3个默认成员函数:构造函数、析构函数和拷贝函数。
二.构造函数
构造函数是用于初始化对象的特殊成员函数,它的主要任务是初始化对象的域元变量,并不为对象分配内存,确保对象在创建的时候是有效的。
2.1函数名与类名相同C++语法要求,构造函数的名称要和类名相同,这能让编译器识别这个是构造函数而不是普通成员函数。
class MyClass { public: MyClass() { /* 构造函数体 */ } }; 2.2构造函数无返回值构造函数无返回值,甚至不需要void。它的作用仅仅是去初始化对象,不需要任何返回值。
class MyClass { public: MyClass() { /* 构造函数体 */ } }; 2.3 对象实例化时系统会自动调用构造函数在对象实例化时自动调用。开发者不需要显式调用构造函数,编译器会在对象创建时自动执行它。
2.4支持函数重载构造函数支持函数重载,不同的函数可以使用同一个函数名称,但是需要保证函数参数列表是不同的,例如:
class MyClass { public: MyClass() { /* 无参构造函数 */ } MyClass(int x) { /* 带参构造函数 */ } }; 2.5默认构造函数默认构造函数提供了一个基本的初始化方式。如果用户定义了其他形式的构造函数(如带参数的),编译器认为用户不再需要默认构造函数,因此不会自动生成。
2.6无参构造函数与全缺省构造函数与默认构造函数首先声明,这三种函数不能同时存在,三种函数作用相似,初始化对象不需要提供显式参数的函数,但这三个函数任意其一可以和带参数的函数一起存在(函数重载)。
例子:
#include <iostream> using namespace std; class MyClass { public: // 全缺省构造函数 MyClass(int x = 10, int y = 20) { //函数体 } // 普通带参构造函数 MyClass(double z) { //函数体 } }; int main() { MyClass obj1; MyClass obj2(10); MyClass obj3(3.14); return 0; }三、析构函数
析构函数和构造函数的作用相反,它用于在函数的生命周期结束的时候释放资源。
值得说的是,析构函数会在对象销毁时自动调用,以完成对象中资源的清理工作。这一特性使得C++能够有效地管理内存和其他资源,防止资源泄漏。
3.1析构函数名称析构函数名和类名相同,在前面加上一个 ~
class MyClass { public: ~MyClass() { // 析构函数体 } }; 3.2无参数和返回值析构函数是用来清理对象的资源的,不需要参数和返回值。
class MyClass { public: ~MyClass() { // 无参数,无返回值 } }; 3.3一个类只能有一个析构函数C++规定,一个类只能有一个析构函数,因为一个对象只能在生命周期结束时被销毁一次。
class MyClass { public: ~MyClass() { // 只能有一个析构函数 } }; 3.4自动调用当一个对象的生命周期结束(如对象超出作用域或显式删除对象)时,系统会自动调用析构函数来清理资源。
如果显式定义了析构函数,对于自定义类型的成员变量,它们的析构函数也会被自动调用。
class MyClass { private: std::string _name; // 自定义类型成员 public: ~MyClass() { // 自定义类型的成员变量会自动调用其析构函数 } }; 3.5显式写析构函数如果显式定义了析构函数,C++会确保自定义类型的成员变量,在生命周期结束的时候,也会自动调用他的析构函数。
class MYclass { private: std::string_name; public: ~MYclass() {} } 3.6可以不写的情况如果类里没有需要动态分配的资源或者需要手动释放的资源,可以不需要写析构函数,可以使用编译器的默认析构函数。例如:
class Myclass { private: int_value;//没有需要动态分配的资源 } 3.7析构函数执行的顺序C++规定,先定义的函数后析构。
这一规则保证了对象按照先进后出的顺序进行销毁,这符合栈的逻辑。
class Myclass { public: ~Myclass() {} }; int main() { Myclass odj 1; Myclass obj 2;//这里2回比1先销毁 return 0; }下面,将用两个具体的代码实例帮助大家理解构造函数和析构函数在C++中的性质和作用。
实例一:利用两个栈实现队列
#include<iostream> using namespace std; typedef int STDataType; class Stack { public: Stack(int n = 4) { _a = (STDataType*)malloc(sizeof(STDataType) * n); if (_a == nullptr) { perror("malloc申请空间失败"); return; } _capacity = n; _top = 0; } ~Stack() { // 自定义析构函数,释放动态分配的内存 cout << "~Stack()" << endl; free(_a); _a = nullptr; _top = _capacity = 0; } private: STDataType* _a; size_t _capacity; size_t _top; }; // 两个Stack实现队列 class MyQueue { public: MyQueue() : pushst(), popst() {} // 默认析构函数自动调用两个Stack成员的析构函数 // 显式定义的析构函数,也会自动调用Stack成员的析构函数 /*~MyQueue() {}*/ private: Stack pushst; Stack popst; }; int main() { Stack st; MyQueue mq; // MyQueue的析构函数会自动调用pushst和popst的析构函数 return 0; }实例二:用C++解决括号匹配
#include<iostream> using namespace std; bool isValid(const char* s) { Stack st; while (*s) { if (*s == '[' || *s == '(' || *s == '{') { st.Push(*s); } else { if (st.Empty()) { return false; } char top = st.Top(); st.Pop(); if ((*s == ']' && top != '[') || (*s == '}' && top != '{') || (*s == ')' && top != '(')) { return false; } } ++s; } return st.Empty(); // 确保所有括号都匹配 } int main() { cout << isValid("[()][]") << endl; // 输出1(true) cout << isValid("[(])[]") << endl; // 输出0(false) return 0; } 四、拷贝构造函数 4.1定义拷贝构造是一种构造函数,用于通过一个已经存在的对象来构造一个新的对象。
在C++中,如果一个函数的第一个参数是自身类型的引用,那么这个函数就是拷贝构造函数。
4.2本质拷贝构造函数本质就是原函数的一个函数重载。
因为定义中讲,如果一个函数的第一个参数是自身类型的引用,那么这个函数就是拷贝构造函数。那么这两个函数的函数名必然相同,只不过参数列表不同,一个是函数本身的参数列表,另一个是同类对象的引用。
4.3第一个参数注意!!拷贝构造函数的第一个参数必须调用类类型对象的引用,不能传值,否则就会出现无限调用拷贝构造,导致编译错误。如下图:
4.4自定义类型对象的拷贝在C++中,无论是传值,还是从函数内部返回一个对象,C++都调用了拷贝函数来创建新的对象。
4.5若没有显式地写,编译器会自动生成如果没有显式的写拷贝函数,编译器会自动生成一个拷贝函数,对函数的内置类型进行拷贝,不过注意,这是浅拷贝,浅拷贝指的是例如简单变量,数组等,可以直接拷贝一份给别的地方用,但是如果遇到例如,栈,这一类需要动态分配资源的,浅拷贝会导致例如两个资源共用一个空间的矛盾产生,这时需要自定义函数来实现深拷贝。
4.6拷贝函数的传值返回在C++中,通过值返回对象时,编译器会调用拷贝构造函数来创建返回值的副本。如果通过引用返回对象,则没有拷贝发生。然而,引用返回需要确保返回的对象在函数结束后仍然存在,否则会导致悬空引用。例如:
MyClass ReturnByValue() { MyClass temp(10); return temp; // 调用拷贝构造函数,返回对象副本 } MyClass& ReturnByReference() { static MyClass temp(10); // 使用static,确保返回的引用有效 return temp; // 返回引用,不调用拷贝构造函数 } int main() { MyClass obj1 = ReturnByValue(); // 调用拷贝构造函数 MyClass& obj2 = ReturnByReference(); // 不调用拷贝构造函数 return 0; }结语
至此,本文介绍的关于C++入门的部分知识正式结束,日后我会更新更多关于C++的基础入门知识,如果本文能帮助到阅读文章的你,就请点赞转发收藏吧,您的支持也是我继续学习和更新的动力,感谢支持!!
C++类和对象入门(二)由讯客互联其他栏目发布,感谢您对讯客互联的认可,以及对我们原创作品以及文章的青睐,非常欢迎各位朋友分享到个人网站或者朋友圈,但转载请说明文章出处“C++类和对象入门(二)”