> 文章列表 > c++ 类的特殊成员函数:构造函数(一)

c++ 类的特殊成员函数:构造函数(一)

c++ 类的特殊成员函数:构造函数(一)

构造函数是类的一种特殊的成员函数,它在每次创建类的新对象时被执行。与类名同名,没有返回值,可以被重载,可以有参,通常用来做初始化工作。

构造函数:

1. 创建类的对象,就会执行类的构造函数

默认情况下,编译器会为每个类添加无参构造函数。
Engineer.h

#ifndef PCL_STUDY_ENGINEER_H
#define PCL_STUDY_ENGINEER_H#include <iostream>class Engineer {
public:std::string ID;std::string post;Engineer();Engineer(std::string ID);Engineer(std::string ID,std::string post);};#endif //PCL_STUDY_ENGINEER_H

无参构造,前面得加 public,不然创建对象时报错:

Calling a private constructor of class 'Engineer' 
implicitly declared private here

Engineer.cpp

Engineer::Engineer(){std::cout << "无参构造 ..." << std::endl;
}Engineer::Engineer(std::string ID){std::cout << "有参构造 --> 单 ..." << std::endl;
}Engineer::Engineer(std::string ID,std::string post){std::cout << "有参构造 --> 双 ..." << std::endl;
}

Create_object.cpp

#include "Engineer.h"int main(){Engineer Engineer_object;Engineer Engineer_object1;return 0;
};

CMakeLists.txt

cmake_minimum_required(VERSION 3.10)
project(pcl_study)set(CMAKE_SYSTEM_NAME Linux)
set(CMAKE_C_COMPILER /usr/bin/x86_64-linux-gnu-gcc) #c编译器
set(CMAKE_CXX_COMPILER /usr/bin/x86_64-linux-gnu-g++) #c++编译器# ${CMAKE_CURRENT_SOURCE_DIR} == ${PROJECT_SOURCE_DIR}# 设置输出根目录为# /${CMAKE_BUILD_TYPE}
set(OUTPUT_DIRECTORY_ROOT ${CMAKE_CURRENT_SOURCE_DIR})
# 设置可执行程序输出到bin目录
set(CMAKE_RUNTIME_OUTPUT_DIRECTORY "${OUTPUT_DIRECTORY_ROOT}/bin" CACHE PATH "Runtime directory" FORCE)
# 设置库文件输出到lib目录
set(CMAKE_LIBRARY_OUTPUT_DIRECTORY "${OUTPUT_DIRECTORY_ROOT}/lib" CACHE PATH "Library directory" FORCE)
set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY "${OUTPUT_DIRECTORY_ROOT}/lib" CACHE PATH "Archive directory" FORCE)add_executable(create_object Create_object.cpp Engineer.cpp)

运行的时候:

无参构造 ...
无参构造 ...

创建了两个对象,执行了两次无参构造。

2. 构造函数重载,成有参构造

Create_object.cpp

#include "Engineer.h"int main(){Engineer Engineer_object;Engineer Engineer_object1;Engineer Engineer_object2("00001");Engineer Engineer_object3("00001","Algorithm engineer");return 0;
};

运行结果:

无参构造 ...
无参构造 ...
有参构造 -->...
有参构造 -->...

注意:

Engineer Engineer_object0();

是函数的声明,声明一个返回值类型为Engineer ,没有参数的 Engineer_object0 函数,
不是创建一个对象.
clion 的提示词也可看出

Function 'Engineer_object0' is never used 

3. 只要在类中创建了构造函数,编译器就不会添加无参构造函数

Engineer.h

#ifndef PCL_STUDY_ENGINEER_H
#define PCL_STUDY_ENGINEER_H#include <iostream>class Engineer {std::string ID;std::string post;public://    Engineer();Engineer(std::string ID ID);Engineer(std::string ID ID,std::string post);};#endif //PCL_STUDY_ENGINEER_H

此时

Engineer Engineer_object;

报错:

No matching constructor for initialization of 'Engineer' 
candidate constructor not viable: requires single argument 'ID', but no arguments were provided 
candidate constructor (the implicit copy constructor) not viable: requires 1 argument, but 0 were provided 
candidate constructor (the implicit move constructor) not viable: requires 1 argument, but 0 were provided 
candidate constructor not viable: requires 2 arguments, but 0 were provided没有用于初始化“Engineer”的匹配构造函数
候选构造函数不可行:需要单个参数“ID”,但未提供任何参数
候选构造函数(隐式复制构造函数)不可行:需要1个参数,但提供了0个
候选构造函数(隐式移动构造函数)不可行:需要1个参数,但提供了0个
候选构造函数不可行:需要2个参数,但提供了0个

4. 构造函数是用来初始化类的成员变量

4.1 先创建对象,再对对象的成员赋值

...
Engineer Engineer_object;
Engineer_object.ID = "00000";
Engineer_object.post = "Algorithm engineer";
...

4.2 通过有参构造函数,创建对象的同时,赋值给成员变量

Create_object.cpp

Engineer Engineer_object3("00001","Architecture engineer");

Engineer.cpp

...
Engineer::Engineer(std::string ID,std::string post){ID = ID;post = post;std::cout << "有参构造 --> 双 ..." << std::endl;std::cout << "--" <<post << " 的工号是 : "<< ID<<"--"<< std::endl;
}
...

运行结果:

有参构造 -->...
--Architecture engineer 的工号是 : --

结果不完整,根据参数范围的就近原则

ID = ID;
post = post;

上面的两个ID 都是函数的局部变量std::string ID, 两个 post 都是函数的局部变量std::string post ,与上面有参构造函数外的的类的成员变量没关系.

4.2.1 可改成:

Engineer::Engineer(std::string number,std::string position){ID = number;post = position;std::cout << "有参构造 --> 双 ..." << std::endl;std::cout << "--" <<post << " 的工号是 : "<< ID<<"--"<< std::endl;
}

运行结果:

--Architecture engineer 的工号是 : 00002--

4.2.2 也可改成:

Engineer::Engineer(std::string ID,std::string post){Engineer::ID = ID;Engineer::post = post;std::cout << "有参构造 --> 双 ..." << std::endl;std::cout << "--" <<post << " 的工号是 : "<< ID<<"--"<< std::endl;
}

运行结果:

--Architecture engineer 的工号是 : 00002--

4.2.3 还可改成:

Engineer::Engineer(std::string ID,std::string post){this->ID = ID;this->post = post;std::cout << "有参构造 --> 双 ..." << std::endl;std::cout << "--" <<post << " 的工号是 : "<< ID<<"--"<< std::endl;
}

运行结果:

--Architecture engineer 的工号是 : 00002--

上面的三种本质上是先声明,再赋值.类似于:

int num;
num = 18;

5. 初始化列表的形式完成类的成员变量的初始化

在上面类的成员变量的初始化时,是在构造函数的函数体里面完成的。如果使用初始化列表,那么成员变量的初始化赋值是在函数体执行前完成,并且初始化列表有一个优点是: 防止类型收窄,换句话说就是精度丢失
初始化列表的形式为:

Engineer::Engineer(std::string ID,std::string post):ID{ID},post{post}{std::cout << "有参构造 --> 双 ..." << std::endl;std::cout << "--" <<post << " 的工号是 : "<< ID<<"--"<< std::endl;
}

也可为:

Engineer::Engineer(std::string ID,std::string post):ID{ID},post{post}{std::cout << "有参构造 --> 双 ..." << std::endl;std::cout << "--" <<post << " 的工号是 : "<< ID<<"--"<< std::endl;
}

类似为:

int num {18};
int num (18);
int num = 18;

使用到构造函数初始化列表的情况:

一、需要初始化的成员变量是对象的情况(这里包含了继承情况下,
通过显示调用父类的构造函数对父类成员变量进行初始化);
二、需要初始化const修饰的类成员或初始化引用成员数据;
三、子类初始化父类的私有成员;