目录
- 一、构造函数:初始化的核心
- 二、对象初始化的具体方式
- 1. 默认初始化(无参构造函数)
- 2. 带参数的构造函数初始化
- 3. 成员初始化列表(推荐)
- 4. 拷贝构造函数初始化
- 5. 列表初始化(C++11 及以上)
- 6. 委托构造函数(C++11 及以上)
- 7. 聚合类的初始化
- 8. 动态对象初始化(new关键字)
- 三、初始化与赋值的区别
- 总结
在 C++ 中,类的对象初始化是创建对象时为其成员变量赋予初始值的过程,核心依赖构造函数(类的特殊成员函数)。根据场景和需求,对象初始化有多种方式,下面详细介绍:
一、构造函数:初始化的核心
构造函数是与类同名的特殊成员函数,用于对象创建时的初始化,其特点:
- 无返回值(无需写
void
); - 可重载(定义多个参数不同的构造函数);
- 若未手动定义,编译器会生成默认构造函数(无参,仅为成员变量执行默认初始化)。
二、对象初始化的具体方式
1. 默认初始化(无参构造函数)
当类有默认构造函数(无参构造函数)时,可直接创建对象,无需传递参数。
默认构造函数的来源:
- 手动定义:
类名()
; - 编译器自动生成(仅当未定义任何构造函数时)。
示例:
#include <IOStream> using namespace std; class Person { private: string name; int age; public: // 手动定义默认构造函数 Person() { name = "Unknown"; age = 0; cout << "默认构造函数被调用" << endl; } js void show() { cout << "Name: " << name << ", Age: " << age << endl; } }; int main() { // 默认初始化(调用默认构造函数) Person p1; // 正确:无参构造 p1.show(); // 输出:Name: Unknown, Age: 0 return 0; }
注意:若手动定义了带参构造函数,编译器不再生成默认构造函数,此时需显式定义,否则Person p1;
会报错。
2. 带参数的构造函数初始化
通过自定义带参数的构造函数,在创建对象时传递参数,直接初始化成员变量。
示例:
class Person { private: string name; int age; public: // 带参数的构造函数 Person(string n, int a) { name = n; // 为成员变量赋值 age = a; cout << "带参构造函数被调用" << endl; } void show() { cout << "Name: " << name << ", Age: " << age << endl; } }; int main() { // 用带参构造函数初始化 Person p2("Alice", 18); // 直接传递参数 p2.show(); // 输出:Name: Alice, Age: 18 return 0; }
3. 成员初始化列表(推荐)
构造函数的成员初始化列表用于在进入构造函数体之前,直接初始化成员变量(而非在函数体内赋值)。
适用场景:
- 初始化
const
成员变量(必须在定义时初始化); - 初始化引用成员(
&
,必须在定义时初始化); - 初始化没有默认构造函数的成员对象(如类的成员是另一个类的对象,且该类无默认构造)。
语法:
类名(参数列表) : 成员1(值1), 成员2(值2)www.devze.com, ... { // 构造函数体(可空) }
示例:
class Person { private: string name; const int age; // const成员,必须初始化 int& id; // 引用成员,必须初始化 public: // 成员初始化列表:直接初始化成员 Person(string n, int a, int& i) : name(n), age(a), id(i) { // 构造函数体可做其他操作,无需再给成员赋值 cout << "成员初始化列表被使用" &ljavascriptt;< endl; } void show() { cout << "Name: " << name << ", Age: " << age << ", ID: " << id << endl; } }; int main() { int num = 1001; Person p3("Bob", 20, num); // 传递参数到初始化列表 p3.show(); // 输出:Name: Bob, Age: 20, ID: 1001 return 0; }
优势:比在构造函数体内赋值更高效(直接初始化,而非先默认构造再赋值)。
4. 拷贝构造函数初始化
用已存在的对象初始化新对象时,会调用拷贝构造函数。
拷贝构造函数的语法(参数必须是同类对象的const
引用):
类名(const 类名& 已有对象) { // 用已有对象的成员初始化当前对象的成员 }
调用场景:
- 用对象 A 初始化对象 B(
类名 B = A;
或类名 B(A);
); - 对象作为函数参数按值传递;
- 函数返回对象(按值返回)。
示例:
class Person { private: string name; int age; public: // 带参构造函数 Person(string n, int a) : name(n), age(a) {} // 拷贝构造函数(自定义) Person(const Person& other) { name = other.name; // 拷贝other的name age = other.age; // 拷贝other的age cout << "拷贝构造函数被调用" << endl; } void show() { cout << "Name: " << name << ", Age: " << age << endl; } }; int main() { Person p4("Charlie", 22); // 先创建p4 Person p5 = p4; // 用p4初始化pjs5(调用拷贝构造) Person p6(p4); // 另一种写法(同样调用拷贝构造) p5.show(); // 输出:Name: Charlie, Age: 22 p6.show(); // 输出:Name: Charlie, Age: 22 return 0; }
注意:若未手动定义拷贝构造函数,编译器会生成默认拷贝构造函数(浅拷贝)。若类中包含指针成员,浅拷贝可能导致内存问题(需手动实现深拷贝)。
5. 列表初始化(C++11 及以上)
使用大括号{}
初始化对象,支持多种场景,且更安全(防止窄化转换,如int
不能隐式接收double
的小数部分)。
示例:
class Person { private: string name; int age; public: // 带参构造函数(支持列表初始化) Person(string n, int a) : name(n), age(a) {} void show() { cout << name << ", " << age << endl; } }; int main() { // 列表初始化(调用带参构造) Person p7{"David", 25}; // 等价于 Person p7("David", 25); Person p8 = {"Eve", 26}; // 也支持等号+大括号 p7.show(); // David, 25 p8.show(); // Eve, 26 return 0; }
优势:
- 统一初始化语法(可用于内置类型、数组、容器等);
- 防止窄化转换(如
Person p{123.45, "abc"}
会编译报错,因参数类型不匹配)。
6. 委托构造函数(C++11 及以上)
允许一个构造函数调用同一个类的另一个构造函数,减少代码重复。
示例:
class Person { private: string name; int age; public: // 核心构造函数(带参数) Person(string n, int a) : name(n), age(a) { cout << "核心构造函数被调用" << endl; } // 委托构造:调用带参构造函数(默认name为"Unknown",age为0) Person() : Person("Unknown", 0) { cout << "委托构造函数(无参)被调用" << endl; } // 委托构造:调用带参构造函数(仅指定age,name默认"Guest") Person(int a) : Person("Guest", a) { cout << "委托构造函数(仅age)被调用" << endl; } }; int main() { Person p9; // 调用无参委托构造 → 核心构造 Person p10(30); // 调用单参委托构造 → 核心构造 return 0; }
输出:
核心构造函数被调用
委托构造函数(无参)被调用核心构造函数被调用委托构造函数(仅age)被调用
7. 聚合类的初始化
聚合类是一种特殊的类(或结构体),满足:
- 无用户定义的构造函数;
- 无私有 / 保护的非静态成员;
- 无基类;
- 无虚函数。
聚合类可直接用初始化列表初始化成员(按成员声明顺序)。
示例:
// 聚合类(结构体,满足聚合类条件) struandroidct Student { string name; // 公有成员 int age; float score; }; int main() { // 直接初始化聚合类的成员(按声明顺序) Student s1 = {"Frank", 19, 90.5}; Student s2{"Grace", 20, 88.0}; // C++11列表初始化 cout << s1.name << ", " << s1.age << ", " << s1.score << endl; // Frank, 19, 90.5 return 0; }
8. 动态对象初始化(new关键字)
用new
创建堆上的对象时,需显式调用构造函数初始化,后续用delete
释放。
示例:
class Person { private: string name; public: Person(string n) : name(n) {} void show() { cout << name << endl; } }; int main() { // 动态初始化(堆上创建对象) Person* p11 = new Person("Helen"); // 调用带参构造 Person* p12 = new Person{"Ivy"}; // C++11列表初始化 Person* p13 = new Person(); // 调用默认构造(若存在) p11->show(); // Helen p12->show(); // Ivy // 释放堆内存 delete p11; delete p12; delete p13; return 0; }
三、初始化与赋值的区别
- 初始化:对象创建时赋予初始值(调用构造函数或初始化列表),仅执行一次;
- 赋值:对象创建后,通过赋值运算符(
=
)修改成员变量,可执行多次。
对const
成员、引用成员等,只能初始化,不能赋值。
总结
C++ 对象初始化方式多样,核心是通过构造函数实现,根据场景选择:
- 简单初始化:用默认构造或带参构造;
- 高效 / 特殊成员(
const
、引用):用成员初始化列表; - 复用对象:用拷贝构造;
- 简洁安全:用列表初始化(
{}
); - 减少代码重复:用委托构造。
到此这篇关于c++中类的对象初始化的实现示例的文章就介绍到这了,更多相关c++ 类对象初始化内容请搜索编程客栈(www.devze.com)以前的文章或继续浏览下面的相关文章希望大家以后多多支持编程客栈(www.devze.com)!
精彩评论