网站首页 > 基础教程 正文
- 类的构造函数
类的构造函数是类的一种特殊的成员函数,主要用于对象分配空间,进行初始化,它会在每次创建类的新对象时执行。
构造函数的特殊性质
1)构造函数的名字必须与类名相同。
2)构造函数可以有任意类型的参数,并且不会返回任何类型,也不会返回void。
3)构造函数的函数体可写在类体内,也可以在类体外。
4)构造函数可以重载,即一个类中可以定义多个参数或参数类型不同的构造函数。
5)构造函数是不能继承的。
6)构造函数被声明为公有函数,但不能像其他成员函数一样被显示调用,它会在每次创建类的新对象时执行。
7) 若在类中没有定义类的构造函数,编译器会自动生成一个无参数的默认形式的构造函数。
8) 构造函数在定义类的对象时系统自动调用,用户不能私自调用。
9)构造函数的调用顺序是在对象进入其作用域时(对象使用之前),调用构造函数。先创建的对象先调用构造函数,后创建的对象后调用构造函数。
10)类的构造函数一般作为类的公有( public )成员函数,在创建对象时可成功调用构造函数,若作为私有( private )或( protected )成员函数,在类外创建对象时是无法访问的。
11)使用没有形参的构造函数时,定义对象时不需要加括号,使用有形参的构造函数,如果形参全部有默认值,也可以不传参数,也是不用加括号。
12)构造函数除了对数据成员进行赋值外,还可以利用初始化列表对数据成员进行初始化,参数列表只需要在定义的时候写上就行了,初始化和赋值的区别在于,初始化是数据成员在定义的时候完成的(像int a = 10; 这是初始化 ),赋值是数据成员定义之后进行的( 像 int b; b = 12; 这是赋值 ),在重载的情况中,执行哪个构造函数就执行哪个初始化列表。
定义构造函数的一般形式
利用构造函数直接创建对象.其一般形式为:类名 对象名;
#include <iostream>
class Solution
{
public:
Solution() {}
~Solution() {}
void set_num(int n) { num = n; }
int get_num() { return num; }
private:
int num;
};
int main()
{
Solution ss;
ss.set_num(2);
std::cout << ss.get_num() << std::endl;
return 0;
}
定义初始化列表的构造函数
带有成员初始化表的构造函数的一般形式如下: 类名::构造函数名(参数表): (成员初始化表){ 构造函数体 }。
类成员是按照它们在类里被声明的顺序初始化的,与它们在初始化表中列出的顺序无关。
#include <iostream>
class Solution
{
public:
Solution() {}
Solution(int n1, int n2) :num1(n1), num2(n2) {}
Solution(const char* str)
{
int len = strlen(str);
name = (char*)malloc(len + 1); //注意要\0结束符
strcpy(name, str);
}
~Solution()
{
if (nullptr != name)
{
free(name);
name = nullptr; //一定要赋值nullptr
}
}
int get_sum() { return num1 + num2; }
void print_name() { std::cout << name << std::endl; }
private:
int num1;
int num2;
char* name;
};
int main()
{
Solution ss1(1, 2);
Solution ss2("Tom");
std::cout << ss1.get_sum() << std::endl;
ss2.print_name();
return 0;
}
使用指针和new来实现创建对象
其一般语法形式为: 类名 *指针变量 = new 类名 (实参表)
#include <iostream>
class Solution
{
public:
Solution() {}
Solution(int n):num(n) {}
~Solution() {}
void set_num(int n) { num = n; }
int get_num() { return num; }
private:
int num;
};
int main()
{
Solution *ss1 = new Solution;
ss1 ->set_num(2);
std::cout << ss1 ->get_num() << std::endl;
?
Solution *ss2 = new Solution(4);
std::cout << ss2 ->get_num() << std::endl;
return 0;
}
缺省参数的构造函数
初始化对象时,输入参数可以写,也可以不写;不写时则为默认值。
#include <iostream>
class Solution
{
public:
Solution(int a = 0) { num = a; }
~Solution() {}
void set_num(int n) { num = n; }
int get_num() { return num; }
private:
int num;
};
int main()
{
Solution ss1; //默认a = 0;
std::cout << ss1.get_num() << std::endl;
return 0;
}
拷贝构造函数
拷贝构造本质上也是构造函数;参数是所在类的常引用的构造函数;类中默认的拷贝构造函数,实现的是逐个复制非静态成员(成员的复制称为浅复制)值,复制的是成员的值,这种类中默认的拷贝构造函数实现的过程被称为浅拷贝。
(1) 用一个对象去初始化另外一个对象
#include <iostream>
class Solution
{
public:
Solution() {}
Solution(int n): num(n) {}
Solution(const Solution& ss) //拷贝构造函数
{
num = ss.num;
}
~Solution() {}
void set_num(int n) { num = n; }
int get_num() { return num; }
private:
int num;
};
int main()
{
Solution ss1(1);
Solution ss2(2);
ss1 = ss2; //ss2简单赋值给ss1,不调用拷贝构造函数
std::cout << ss1.get_num() << std::endl;
std::cout << ss2.get_num() << std::endl;
Solution ss3 = ss2; //ss2初始化ss3,调用拷贝构造函数
std::cout << ss3.get_num() << std::endl;
Solution ss4(ss2); //ss2初始化ss4,调用拷贝构造函数
std::cout << ss4.get_num() << std::endl;
return 0;
}
(2) 函数中类对象作为形参
#include <iostream>
class Solution
{
public:
Solution() {}
Solution(int n): num(n) {}
Solution(const Solution& ss)
{
num = ss.num;
}
~Solution() {}
void set_num(int n) { num = n; }
int get_num() { return num; }
private:
int num;
};
void function(Solution ss)
{
ss.set_num(5);
std::cout << ss.get_num() << std::endl;
}
int main()
{
Solution ss1(1);
function(ss1); // function函数初始化形参ss会调用拷贝构造函数创建一个副本。
return 0;
}
(3) 构造函数的匿名对象
#include <iostream>
class Solution
{
public:
Solution() {}
Solution(int n): num(n) {}
Solution(const Solution& ss)
{
num = ss.num;
}
~Solution() {}
void set_num(int n) { num = n; }
int get_num() { return num; }
private:
int num;
};
//functionA会返回一个新对象:匿名对象
Solution functionA()
{
Solution A(4);
return A;
}
void functionB()
{
Solution ss = functionA();//用匿名对象初始化ss,此时c++编译器直接把匿名对转成ss;(扶正) 从匿名转成有名字了ss
printf("匿名对象,被扶正,不会析构掉\n");
ss.set_num(6);
std::cout << ss.get_num() << std::endl;
}
void functionC()
{
Solution ss(2);
ss = functionA(); //用匿名对象赋值给ss后, 匿名对象被析构
printf("因为用匿名对象赋值给ss, 匿名对象被析构\n");
ss.set_num(6);
std::cout << ss.get_num() << std::endl;
}
int main()
{
functionB();
functionC();
return 0;
}
- 类的析构函数
1)析构函数是类的一种特殊的成员函数,它会在每次删除所创建的对象时执行。
2)析构函数的名称与类的名称是相同的,只是在前面加了个波浪号(~)作为前缀。
3)析构函数不会返回任何值,不能带有任何参数,也不可以被重载,可以为虚函数。
4)析构函数必须为公有public。
5)没有析构函数,编译器会自动生成默认析构函数。
6)一个类中只能拥有一个析构函数。
7)new申请内存,必须提供适当析构函数。
8)析构顺序是最后创建的对象先被析构。
9)析构函数有助于在跳出程序(比如关闭文件、释放内存等)前释放资源。
举个例子:
#include <iostream>
class Solution
{
public:
Solution(int n):num(n) { std::cout << "Solution constructor " << num << std::endl; }
~Solution() { std::cout << "Solution distructor" << num << std::endl; }
private:
int num;
};
int main()
{
Solution ss1(1);
Solution ss2(2);
Solution ss3(3);
system("pause");
return 0;
}
运行结果:
构造函数调用顺序为:ss1->ss2->ss3
析构函数调用顺序为:ss3->ss2->ss1
- 上一篇: c++——默认成员函数 c++成员变量默认值
- 下一篇: C++的23种设计模式(上篇-创建型模式)
猜你喜欢
- 2024-10-12 全面剖析 C++ Boost 智能指针!| CSDN 博文精选
- 2024-10-12 C++设计模式——原型模式 设计模式之原型模式
- 2024-10-12 如何攻克 C++ 中复杂的类型转换? c++中四种类型转换的方式
- 2024-10-12 C++|由成员函数到运算符重载(类内、类外、友元方式重载)
- 2024-10-12 C++11新特性(49)- 用移动类对象代替拷贝类对象
- 2024-10-12 C++类的默认成员函数 c++类中定义的成员默认访问属性为( )
- 2024-10-12 C++的23种设计模式(上篇-创建型模式)
- 2024-10-12 c++——默认成员函数 c++成员变量默认值
- 2024-10-12 C++|类中实现操作符重载,用操作符代替成员函数名
- 2024-10-12 C++之构造与析构 c++构造类
- 最近发表
- 标签列表
-
- gitpush (61)
- pythonif (68)
- location.href (57)
- tail-f (57)
- pythonifelse (59)
- deletesql (62)
- c++模板 (62)
- css3动画 (57)
- c#event (59)
- linuxgzip (68)
- 字符串连接 (73)
- nginx配置文件详解 (61)
- html标签 (69)
- c++初始化列表 (64)
- exec命令 (59)
- canvasfilltext (58)
- mysqlinnodbmyisam区别 (63)
- arraylistadd (66)
- node教程 (59)
- console.table (62)
- c++time_t (58)
- phpcookie (58)
- mysqldatesub函数 (63)
- window10java环境变量设置 (66)
- c++虚函数和纯虚函数的区别 (66)