C++ 对象常见构造函数与赋值运算符
C++ 对象常见构造函数与赋值运算符
对象常见构造函数与赋值运算符如下:
- 普通构造函数 (Default constructor)
- 参数化构造函数 (Parameterized constructor)
- 拷贝构造函数 (Copy constructor)
- 拷贝赋值运算符 (Copy assignment operator)
- 移动构造函数 (Move constructor) (C++11引入)
- 移动赋值运算符 (Move assignment operator) (C++11引入)
- 析构函数 (Destructor)
- 委托构造函数(Delegating Constructor)
准备工作
创建一个标准的bean类Person
class Person {
private:
std::string name;
int age;
std::string gender;
public:
Person(std::string name, int age, std::string gender) : name(name), age(age), gender(gender){
std::cout << std::format("Person Constructor name: {}, age: {}, gender: {}", name, age, gender) << "\n";
}
~Person(){
std::cout << std::format("Person Destructor name: {}, age: {}, gender: {}", name, age, gender) << "\n";
}
friend std::ostream& operator<<(std::ostream& os, const Person& person) {
os << std::format("name: {}, age: {}, gender: {}", person.name, person.age, person.gender);
return os;
}
std::string getName() const {
return name;
}
int getAge() const {
return age;
}
std::string getGender() const {
return gender;
}
void setName(const std::string name) {
this->name = name;
}
void setAge(const int age) {
this->age = age;
}
void setGender(const std::string gender){
this->gender = gender;
}
};
默认构造函数 (Default constructor)
class Person {
private:
std::string name;
int age;
std::string gender;
public:
Person() : name(""), age(0), gender(""){
std::cout << "Person Default Constructor" << "\n";
}
Person(std::string name, int age, std::string gender) : name(name), age(age), gender(gender){
std::cout << std::format("Person Constructor name: {}, age: {}, gender: {}", name, age, gender) << "\n";
}
~Person(){
std::cout << std::format("Person Destructor name: {}, age: {}, gender: {}", name, age, gender) << "\n";
}
friend std::ostream& operator<<(std::ostream& os, const Person& person) {
os << std::format("name: {}, age: {}, gender: {}", person.name, person.age, person.gender);
return os;
}
std::string getName() const {
return name;
}
int getAge() const {
return age;
}
std::string getGender() const {
return gender;
}
void setName(const std::string name) {
this->name = name;
}
void setAge(const int age) {
this->age = age;
}
void setGender(const std::string gender){
this->gender = gender;
}
};
namespace learn01{
void learn01(){
Person p;
std::cout << p << "\n";
p.setName("lisi");
std::cout << p << "\n";
}
}
2. 参数化构造函数 (Parameterized constructor)
class Person {
private:
std::string name;
int age;
std::string gender;
public:
Person() : name(""), age(0), gender(""){
std::cout << "Person Default Constructor" << "\n";
}
Person(std::string name, int age, std::string gender) : name(name), age(age), gender(gender){
std::cout << std::format("Person Constructor name: {}, age: {}, gender: {}", name, age, gender) << "\n";
}
~Person(){
std::cout << std::format("Person Destructor name: {}, age: {}, gender: {}", name, age, gender) << "\n";
}
friend std::ostream& operator<<(std::ostream& os, const Person& person) {
os << std::format("name: {}, age: {}, gender: {}", person.name, person.age, person.gender);
return os;
}
std::string getName() const {
return name;
}
int getAge() const {
return age;
}
std::string getGender() const {
return gender;
}
void setName(const std::string name) {
this->name = name;
}
void setAge(const int age) {
this->age = age;
}
void setGender(const std::string gender){
this->gender = gender;
}
};
namespace learn01{
void learn01(){
auto person = std::make_unique<Person>("Alice", 18, "女");
std::cout << *person << std::endl;
}
}
3. 拷贝构造函数 (Copy constructor)
拷贝构造的三种调用方式。
方式一:
class Person {
private:
std::string name;
int age;
std::string gender;
public:
Person() : name(""), age(0), gender(""){
std::cout << "Person Default Constructor" << "\n";
}
Person(std::string name, int age, std::string gender) : name(name), age(age), gender(gender){
std::cout << std::format("Person Constructor name: {}, age: {}, gender: {}", name, age, gender) << "\n";
}
Person(const Person& other) : name(other.name), age(other.age), gender(other.gender){
std::cout << std::format("Person Copy Constructor name: {}, age: {}, gender: {}", name, age, gender) << "\n";
}
~Person(){
std::cout << std::format("Person Destructor name: {}, age: {}, gender: {}", name, age, gender) << "\n";
}
friend std::ostream& operator<<(std::ostream& os, const Person& person) {
os << std::format("name: {}, age: {}, gender: {}", person.name, person.age, person.gender);
return os;
}
std::string getName() const {
return name;
}
int getAge() const {
return age;
}
std::string getGender() const {
return gender;
}
void setName(const std::string name) {
this->name = name;
}
void setAge(const int age) {
this->age = age;
}
void setGender(const std::string gender){
this->gender = gender;
}
};
namespace learn01{
void learn01(){
Person p1("Alice", 30, "女");
std::cout << p1 << "\n";
Person p2 = p1; // 调用拷贝构造函数
p2.setName("Bob");
p2.setAge(25);
p2.setGender("男");
std::cout << p2 << "\n";
}
}
方式二:
Person p2(p1); // 调用拷贝构造函数
方式三:
static void printPerson(Person person) {
person.setName("Bob");
person.setAge(25);
person.setGender("男");
std::cout << person << "\n";
}
namespace learn01{
void learn01(){
Person p1("Alice", 30, "女");
printPerson(p1);
std::cout << p1 << "\n";
}
}
可以看到将p1参数传递给printPerson函数时进行了一次拷贝构造函数调用。
如果只是简单打印无需拷贝构造函数调用。
static void printPerson(const Person& person) {
std::cout << person << "\n";
}
拷贝赋值运算符 (Copy assignment operator)
class Person {
private:
std::string name;
int age;
std::string gender;
public:
Person() : name(""), age(0), gender(""){
std::cout << "Person Default Constructor" << "\n";
}
Person(std::string name, int age, std::string gender) : name(name), age(age), gender(gender){
std::cout << std::format("Person Constructor name: {}, age: {}, gender: {}", name, age, gender) << "\n";
}
Person(const Person& other) : name(other.name), age(other.age), gender(other.gender){
std::cout << std::format("Person Copy Constructor name: {}, age: {}, gender: {}", name, age, gender) << "\n";
}
~Person(){
std::cout << std::format("Person Destructor name: {}, age: {}, gender: {}", name, age, gender) << "\n";
}
Person& operator=(const Person& other){
if(this != &other){
name = other.name;
age = other.age;
gender = other.gender;
}
std::cout << std::format("Person Copy Assignment Operator name: {}, age: {}, gender: {}", name, age, gender) << "\n";
return *this;
}
friend std::ostream& operator<<(std::ostream& os, const Person& person) {
os << std::format("name: {}, age: {}, gender: {}", person.name, person.age, person.gender);
return os;
}
std::string getName() const {
return name;
}
int getAge() const {
return age;
}
std::string getGender() const {
return gender;
}
void setName(const std::string name) {
this->name = name;
}
void setAge(const int age) {
this->age = age;
}
void setGender(const std::string gender){
this->gender = gender;
}
};
namespace learn01{
void learn01(){
Person p1("Alice", 30, "女");
p1 = p1; // 自我赋值测试 // 1
std::cout << p1 << "\n";
Person p2 = p1; // 拷贝构造测试 // 2
p2.setName("Bob");
p2.setAge(25);
p2.setGender("男");
std::cout << p2 << "\n";
p1 = p2; // 赋值测试
std::cout << p1 << "\n";
}
}
主要记得区分赋值和拷贝构造的区别。
移动构造函数
方式1
class Person {
private:
std::string name;
int age;
std::string gender;
public:
Person() : name(""), age(0), gender(""){
std::cout << "Person Default Constructor" << "\n";
}
Person(std::string name, int age, std::string gender) : name(name), age(age), gender(gender){
std::cout << std::format("Person Constructor name: {}, age: {}, gender: {}", name, age, gender) << "\n";
}
Person(const Person& other) : name(other.name), age(other.age), gender(other.gender){
std::cout << std::format("Person Copy Constructor name: {}, age: {}, gender: {}", name, age, gender) << "\n";
}
Person(Person&& other) noexcept : name(std::move(other.name)), age(std::exchange(other.age, 0)), gender(std::move(other.gender)){
std::cout << std::format("Person Move Constructor name: {}, age: {}, gender: {}", name, age, gender) << "\n";
}
~Person(){
std::cout << std::format("Person Destructor name: {}, age: {}, gender: {}", name, age, gender) << "\n";
}
Person& operator=(const Person& other){
if(this != &other){
name = other.name;
age = other.age;
gender = other.gender;
}
std::cout << std::format("Person Copy Assignment Operator name: {}, age: {}, gender: {}", name, age, gender) << "\n";
return *this;
}
friend std::ostream& operator<<(std::ostream& os, const Person& person) {
os << std::format("name: {}, age: {}, gender: {}", person.name, person.age, person.gender);
return os;
}
std::string getName() const {
return name;
}
int getAge() const {
return age;
}
std::string getGender() const {
return gender;
}
void setName(const std::string name) {
this->name = name;
}
void setAge(const int age) {
this->age = age;
}
void setGender(const std::string gender){
this->gender = gender;
}
};
static void printPerson(Person p){
std::cout << "printPerson: " << p << std::endl;
}
namespace learn01{
void learn01(){
Person p("Alice", 30, "女");
std::cout << p << std::endl;
printPerson(std::move(p)); // 1
// printPerson(p);
p.setName("Bob");
p.setAge(25);
p.setGender("男");
std::cout << p << std::endl;
}
}
使用移动构造函数不会触发拷贝构造函数。
方式二
namespace learn01{
void learn01(){
Person p("Alice", 30, "女");
std::cout << p << std::endl;
Person p2 = std::move(p); // 2
p2.setName("Bob");
p2.setAge(25);
p2.setGender("男");
std::cout << p << std::endl;
std::cout << p2 << std::endl;
}
}
方式三
namespace learn01{
void learn01(){
Person p("Alice", 30, "女");
std::cout << p << std::endl;
Person p2(std::move(p)); // 2
p2.setName("Bob");
p2.setAge(25);
p2.setGender("男");
std::cout << p << std::endl;
std::cout << p2 << std::endl;
}
}
- &: 左值只的是引用
- &&:右值指的是值
拷贝消除(Copy Elision) 优化
Person p = Person("Alice", 30, "女");
此代码相当于直接Person p2("Bob", 25, "男");
移动赋值运算符 (Move assignment operator) (C++11引入)
作用:将临时对象(右值)的资源移动给已存在的对象。
class Person {
private:
std::string name;
int age;
std::string gender;
public:
Person() : name(""), age(0), gender(""){
std::cout << "Person Default Constructor" << "\n";
}
Person(std::string name, int age, std::string gender) : name(name), age(age), gender(gender){
std::cout << std::format("Person Constructor name: {}, age: {}, gender: {}", name, age, gender) << "\n";
}
Person(const Person& other) : name(other.name), age(other.age), gender(other.gender){
std::cout << std::format("Person Copy Constructor name: {}, age: {}, gender: {}", name, age, gender) << "\n";
}
Person(Person&& other) noexcept : name(std::move(other.name)), age(std::exchange(other.age, 0)), gender(std::move(other.gender)){
std::cout << std::format("Person Move Constructor name: {}, age: {}, gender: {}", name, age, gender) << "\n";
}
~Person(){
std::cout << std::format("Person Destructor name: {}, age: {}, gender: {}", name, age, gender) << "\n";
}
Person& operator=(const Person& other){
if(this != &other){
name = other.name;
age = other.age;
gender = other.gender;
}
std::cout << std::format("Person Copy Assignment Operator name: {}, age: {}, gender: {}", name, age, gender) << "\n";
return *this;
}
Person& operator=(Person&& other) noexcept {
if(this != &other){
name = std::move(other.name);
age = std::exchange(other.age, 0);
gender = std::move(other.gender);
}
std::cout << std::format("Person Move Assignment Operator name: {}, age: {}, gender: {}", name, age, gender) << "\n";
return *this;
}
friend std::ostream& operator<<(std::ostream& os, const Person& person) {
os << std::format("name: {}, age: {}, gender: {}", person.name, person.age, person.gender);
return os;
}
std::string getName() const {
return name;
}
int getAge() const {
return age;
}
std::string getGender() const {
return gender;
}
void setName(const std::string name) {
this->name = name;
}
void setAge(const int age) {
this->age = age;
}
void setGender(const std::string gender){
this->gender = gender;
}
};
namespace learn01{
void learn01(){
Person p;
std::cout << p << std::endl;
p = Person("Alice", 30, "女");
std::cout << p << std::endl;
}
}
析构函数
~Person(){
std::cout << std::format("Person Destructor name: {}, age: {}, gender: {}", name, age, gender) << "\n";
}
C++中使用的是RAII(Resource Acquisition Is Initialization)思想,中文常译为 "资源获取即初始化"。它是 C++ 中最核心、最重要的编程理念和设计哲学之一。
举个例子
class FileReader{
private:
std::string filename;
std::ifstream fileStream;
public:
explicit FileReader(const std::string& filename) : filename(filename) {
std::cout << "FileReader constructed for file: " << filename << std::endl;
fileStream.open(filename);
if (!fileStream.is_open()) {
throw std::runtime_error("Could not open file: " + filename);
}
}
~FileReader() {
std::cout << "FileReader destructed for file: " << filename << std::endl;
if (fileStream.is_open()) {
fileStream.close();
}
}
void read() {
std::string line;
while (std::getline(fileStream, line)) {
std::cout << line << std::endl;
}
}
};
namespace learn01{
void learn01(){
try {
auto cores = std::thread::hardware_concurrency();
std::cout << "Hardware concurrency (number of cores): " << cores << "\n";
FileReader reader("D:/SoftWare/LanguageProjects/C++Projects/learn01/main.cpp");
reader.read();
}
catch(const std::exception& e) {
std::cerr << e.what() << '\n';
}
}
}
委托构造函数(Delegating Constructor)
Person(std::string name, int age) : Person(){
this->name = name;
this->age = age;
std::cout << std::format("Person Constructor name: {}, age: {}", name, age) << "\n";
}
顾名思义将一个构造函数委托给另一个构造函数。
区分std::vector的push_back和emplace_back的区别
void learn03(){
Person p("Bob", 30, "男");
std::vector<Person> people;
people.push_back(p); // 调用拷贝构造函数 // 1
// people.emplace_back(p); // 调用拷贝构造函数 // 2
// people.push_back(Person("Alice", 12, "女")); // 调用移动构造函数
// people.emplace_back("Alice", 12, "女"); // 直接在容器内构造对象,避免不必要的拷贝或移动
}
- 非临时对象
push_back和emplace_back效果一致 - 临时对象优先使用
emplace_back,它可以避免不必要的拷贝或移动
C++的构造函数学习完毕,有什么不足还请大家指出。
给大家推荐一C++个学校网站: C++学习网

C++ 对象常见构造函数与赋值运算符
浙公网安备 33010602011771号