C++构造函数简单用法

摘要:
构造函数名称与类名相同。它可以有参数,但不能返回值。构造函数用于初始化对象,例如为变量分配初始值。生成对象时,构造函数会自动调用。一个类可以有多个构造函数。析构函数对象死亡时自动调用
个人笔记,仅供复习
1.构造函数

1.1 基本概念:

  • 每个类都有构造函数,如果自己不写,编译器会生成一个默认的无参数构造函数。
  • 构造函数名字与类名相同,可以有参数,不可以有返回值(void也不可以)。
  • 构造函数的作用是对对象进行初始化,如给变量赋初值。

1.2 注意:

  • 如果定义了构造函数,则编译器不生成默认的无参数构造函数。
  • 对象生成时构造函数自动被调用。对象一旦生成,就再也不能在其上执行构造函数。
  • 一个类可以有多个构造函数(函数重载)。
  • 对象生成调用的可能是构造函数或复制构造函数。

1.3 构造函数的意义:

构造函数执行必要的初始化工作,有了构造函数就不必再写初始化函数,也不用担心对象没有初始化。

1.4 代码实例:

#include<iostream>
#include<string>
using namespace std;
class Myclass{
	private :
		int int_a;
		string str;
	public :
		Myclass(int x = 0,string y = "123"){
			int_a = x;
			str = y;
		}
		void print(){
			cout << int_a << " " << str << endl;
		}
};
int main()
{
	Myclass mc(1,"456");
	mc.print();
	return 0;
}

1.5 可以有多个构造函数,参数个数或类型不同(函数重载):

1.5.1 冒号语法在构造函数中用法:用在构造函数后表示:初始化列表

构造函数初始化时必须采用初始化列表一共有三种情况:

  1. 需要初始化的数据成员是成员对象
  2. 需要初始化const 修饰的类成员
  3. 需要初始化引用成员数据
#include<iostream>
#include<string>
using namespace std;
class Myclass{
	private :
		int int_a;
		string str;
	public :
		Myclass(int x,string y):int_a(x),str(y) {}//1
		Myclass(int x):int_a(x) {}//2
		Myclass(string y):str(y) {}//3
		void print(){
			cout << int_a << " " << str << endl;
		}
};
int main()
{
	Myclass mc(1,"456");//调用1
	Myclass mc2(5);//调用2 
	Myclass mc3("abc");//调用3 
	return 0;
}

1.6 构造函数参数可以是类本身:

#include<iostream>
#include<string>
using namespace std;
class Complex {
	private :
		double real, imag;
	public:
		Complex(double r, double i );
		Complex (double r );
		Complex (Complex c1, Complex c2);
};
Complex::Complex(double r, double i) {
real = r; imag = i;
}

Complex::Complex(double r){
	real = r; imag = 0;
}
Complex::Complex (Complex c1, Complex c2){
	real = c1.real+c2.real;
	imag = c1.imag+c2.imag;
}

int main()
{
	Complex c1(3) , c2 (1,0), c3(c1,c2);// c1 = {3, 0}, c2 = {1, 0}, c3 = {4, 0};
	return 0;
}

1.7 构造函数在数组中的使用:

每生成一个类,就调用一次构造函数。生成数组类的时候,可以用 { } 对对应的类调用构造函数。

#include<iostream>
using namespace std;
class Test {
	public:
		Test( int n) { } //(1)
		Test( int n, int m) { } //(2)
		Test() { } //(3)
};
int main()
{
	Test array1[3] = { 1, Test(1,2) };
	// 三个元素分别用(1),(2),(3)初始化
	Test array2[3] = { Test(2,3), Test(1,2) , 1};
	// 三个元素分别用(2),(2),(1)初始化
	Test * pArray[3] = { new Test(4), new Test(1,2) };
	//两个元素分别用(1),(2) 初始化
	return 0;
} 
2.复制构造函数

2.1 基本概念:

  • 只有一个参数,即对同类对象的引用
  • 形如X::X( X& )X::X( const X &),二者选一,后者能以常量对象作为参数
  • 如果没有定义复制构造函数,那么编译器生成默认复制构造函数。默认的复制构造函数完成复制功能

注:

  • 不允许有形如 X::X( X )的构造函数
  • 如果定义了自己的复制构造函数,那默认复制构造函数将不存在

2.2 复制构造函数起作用的三种情况:

  • 用一个对象去初始化同类的另一个对象
	Complex c2(c1);
	Complex c2 = c1;//初始化语句,非赋值语句。 
  • 如果某函数有一个参数是类A的对象,那么该函数被调用时,类A的复制构造函数将被调用
#include<iostream>
#include<string>
using namespace std;
class A
{
	public:
		A() { };
		A( A & a) {
			cout << "Copy constructor called" <<endl;
		}
};
void Func(A a1){ }
int main(){
	A a2;
	Func(a2);
	return 0;
}
程序输出结果为: Copy constructor called
  • 如果函数的返回值是类A的对象时,则函数返回时,A的复制构造函数被调用
#include<iostream>
#include<string>
using namespace std;
class A
{
	 public:
		 int v;
		 A(int n) { v = n; };
		 A( const A & a) {
			 v = a.v;
			 cout << "Copy constructor called" <<endl;
		 }
};
A Func() {
	A b(4);
	return b;
}
int main() {
	cout << Func().v << endl; 
	return 0;
}

输出结果:Copy constructor called

4

有些编译器会对上述代码进行优化(如dev),那么就只会输出4。

注:对象之间赋值并不导致复制构造函数被调用

2.3 常量引用参数的使用:

void Fun(Myclass obj_){
	cout << "fun" <<endl;
}
这样的函数,调用时生成形参会引发复制构造函数开销比较大可以使用Myclass & 引用类型作为形参。如果希望实参的值不会被改变,可以加上const关键字。3.析构函数

3.1 什么是析构函数:名字与类名相同,在前面加‘~’,没有参数和返回值,一个类最多只能有一个析构函数。

3.2 特点:

  • 名字与类名相同,在前面加‘~’, 没有参数和返回值,一 个类最多只能有一个析构函数。
  • 析构函数对象消亡时即自动被调用。可以定义析构函数来在对象消亡前做善后工作,比如释放分配的空间等。
  • 如果定义类时没写析构函数,则编译器生成缺省析构函数。 缺省析构函数什么也不做。
  • 如果定义了析构函数,则编译器不生成缺省析构函数。

3.3 代码实例:

#include<iostream>
using namespace std;
class A
{
	 public:
		 ~A(){
		 	cout << "now" <<endl;
		 } 
};
void Fun(){
	A a;
}
int main() {
	Fun();
	return 0;
}

当函数调用结束时,局部对象a被释放,析构函数被调用。每当一个对象消亡,就必定会调用析构函数。

3.4 析构函数和数组:对象数组生命期结束时,对象数组的每个元素的析构函数都会被调用。

3.5 析构函数和delete运算符:

  • delete导致析构函数被调用
  • 若new一个对象数组,那么用delete释放时应写[]。否则只delete一个对象(调用一次析构函数)
Ctest  * pTest;
pTest = new Ctest;  //构造函数调用 
delete pTest;          //析构函数调用 
pTest = new Ctest[3]; //构造函数调用3次 
delete [] pTest;           //析构函数调用3次 
4.类型转换构造函数

4.1 基本概念:

  • 定义转换构造函数的目的是实现类型的自动转换
  • 只有一个参数,而且不是复制构造函数的构造函数,一般就可以看作是类型转换构造函数
  • 当需要的时候,编译系统会自动调用类型转换构造函数,建立一个无名的临时对象(或临时变量)

4.2 代码实例:

#include<iostream>
using namespace std;
class A{
	public:
		int first;
		double second;
		A(int a){
			this->first = a;
			this->second = 0.5;
		}
};
int main()
{
	A a = 4;//调用了类型转换构造函数 
	a = 5;//调用了类型转换构造函数 
	cout << a.first << " " << a.second << endl;
	return 0;
}

免责声明:文章转载自《C++构造函数简单用法》仅用于学习参考。如对内容有疑问,请及时联系本站处理。

上篇CH5 ResourceManager重启SQLite学习笔记下篇

宿迁高防,2C2G15M,22元/月;香港BGP,2C5G5M,25元/月 雨云优惠码:MjYwNzM=

相关文章

eigen Matrix详解

Eigen Matrix 详解 在Eigen中,所有的matrices 和vectors 都是模板类Matrix 的对象,Vectors 只是一种特殊的矩阵,行或者列为1. Matrix的前三个模板参数 Matrix 类有6个模板参数,现在我们了解前三个足够。剩下的三个参数都有默认值,后面会探讨,现在不管他。Matrix 的三个强制的模板参数: Matri...

Qt中的QGLWidget简介

我对QGLWidget的理解就是,其从QWidget继承,额外实现了一些OpenGl的操作,归纳如下:1、使用QWidget的句柄winID返回的HWND对OpenGl的绘制设备进行初始化,用一个虚函数initializeGL()实现,用户可以重置这个函数。2、使用resizeGL(int width,int height);对GL的视口进行变换。同样是一...

面试必问:JVM类加载机制详细解析

前言 在Java面试中,简历上有写JVM(Java虚拟机)相关的东西,JVM的类加载机制基本是面试必问的知识点。 类的加载和卸载 JVM是虚拟机的一种,它的指令集语言是字节码,字节码构成的文件是class文件。平常我们写的Java文件,需要编译为class文件才能交给JVM运行。可以这么说:C语言代码——>二进制文件——>计算机硬件,就相当于...

c++中CreateEvent函数

参考:https://blog.csdn.net/u011642774/article/details/52789969 函数原型: [cpp] view plain copy  HANDLE CreateEvent(     LPSECURITY_ATTRIBUTES lpEventAttributes, // SD     BOOL bMan...

Linux等待队列原理与实现

当进程要获取某些资源(例如从网卡读取数据)的时候,但资源并没有准备好(例如网卡还没接收到数据),这时候内核必须切换到其他进程运行,直到资源准备好再唤醒进程。 waitqueue (等待队列) 就是内核用于管理等待资源的进程,当某个进程获取的资源没有准备好的时候,可以通过调用  add_wait_queue() 函数把进程添加到  waitqueue 中,然...

Go第六篇之结构体剖析

Go 语言通过用自定义的方式形成新的类型,结构体是类型中带有成员的复合类型。Go 语言使用结构体和结构体成员来描述真实世界的实体和实体对应的各种属性。 Go 语言中的类型可以被实例化,使用new或&构造的类型实例的类型是类型的指针。 结构体成员是由一系列的成员变量构成,这些成员变量也被称为“字段”。字段有以下特性: 字段拥有自己的类型和值。...