Effective C++ Item 4 确定对象被使用前已先被初始化

本文探讨了C++中为内置对象手工初始化的重要性,并详细对比了使用构造函数本体赋值与成员初始化列表两种方式的区别。通过具体示例展示了不同初始化方法对程序行为的影响。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

本文为senlie原创,转载请保留此地址:http://blog.youkuaiyun.com/zhengsenlie


经验1:为内置对象进行手工初始化,因为C++不保证初始化它们

示例:

int x = 0;//对int进行手工初始化
const char *text = "A C-style string";  //对指针进行手工初始化

double d;
std::cin >> d;//以读取input stream的方式完成初始化


经验2:构造函数最好使用成员初值列 (member initialization list) ,而不要在构造函数本体内使用赋值操作(assignment) 。初值列列出的成员变量,其排列次序应该和它们在 class 中的声明次序相同。

示例1:用赋值操作初始化

#include <iostream>
using namespace std;

class A{
public:
	A(){cout << "default constructor" << endl;};
	A(int v):value(v){};
	A(const A &a2){cout << "copy constructor" << endl;}
	const A& operator=(const A &lhr) const{cout << "operator=" << endl; return *this;}
private:
	int value;
};

class B{
public:
	B(A a2){a = a2;};  //用赋值操作初始化
private:
	A a;
};

int main(){
	A a(1);
	B b(a);  //主要是通过输出看定义b变量调用的函数情况
	system("pause");
}

输出1:

copy constructor      //调用Acopy constructorB构造函数生成参数a2

default constructor    //进入B的构造函数前调用A的默认构造函数定义a

operator=               //调用赋值操作符将a赋值为a2


示例2:使用成员初值列

#include <iostream>
using namespace std;

class A{
public:
	A(){cout << "default constructor" << endl;};
	A(int v):value(v){};
	A(const A &a2){cout << "copy constructor" << endl;}
	const A& operator=(const A &lhr) const{cout << "operator=" << endl; return *this;}
private:
	int value;
};

class B{
public:
	B(A a2):a(a2){};
private:
	A a;
};

int main(){
	A a(1);
	B b(a);
	system("pause");
}

输出2:

copy constructor              //调用Acopy constructorB构造函数生成参数a2

copy constructor              //调用Acopy constructora复制为a2





<think>好的,用户让我讲解Effective C++Item4-5,并且给出测试用例的题目,不需要答案。我需要回顾一下这两个条款的内容。 Effective C++Item4是“确定对象使用初始化”。这里主要讲的是C++初始化和赋值的区别,以及如何正确初始化成员变量。特别是提到构造函数中使用成员初始化列表,而不是在构造函数体内赋值,这样可以提高效率,尤其是对于const成员和引用成员来说,必须使用初始化列表。 Item5是“了解C++默默编写并调用哪些函数”。这部分讨论的是编译器自动生成的函数,即默认构造函数、拷贝构造函数、拷贝赋值运算符和析构函数。当用户没有声明这些函数时,编译器会自动生成它们,但某些情况下(比如类中有引用成员或const成员)编译器可能无法生成拷贝赋值运算符。 接下来用户需要测试用例的题目,不需要答案。我需要设计几个题目,覆盖这两个条款的关键点。 对于Item4,可能的测试题目包括:编写一个类,其中包含不同类型的成员变量(比如int、const int、引用、类对象),要求使用成员初始化列表正确初始化这些成员。另外,可以考察用户是否了解初始化与赋值的区别,比如在构造函数体内赋值导致的问题。 对于Item5,题目可以设计一个类,其中包含引用成员或const成员,然后让用户分析编译器是否会生成默认的拷贝赋值运算符。或者让用户自己声明拷贝构造函数,观察编译器是否还会生成默认的版本。 现在要考虑题目是否清晰,是否能够有效检验对条款的理解。例如,针对Item4,可以设计一个包含const成员和引用成员的类,要求用户写出正确的构造函数。而针对Item5,可以设计一个包含引用成员的类,然后询问拷贝赋值运算符是否可用,或者是否必须用户自己定义。 另外,测试用例的题目可能需要用户编写代码,或者分析代码的问题。例如,给出一个没有使用初始化列表的构造函数,让用户指出问题所在,或者让用户修改代码使其正确初始化成员变量。 需要确保题目覆盖条款中的重点,比如Item4中的成员初始化列表的重要性,以及Item5中编译器自动生成的函数及其限制。同时,题目应该具体,有明确的测试目标,避免过于宽泛。 现在具体构思每个条款的测试题目: Item4的测试题目: 1. 编写一个包含const int成员和引用成员的类,正确实现构造函数。 2. 分析给定的构造函数是否存在效率问题,并优化。 3. 指出在构造函数体内初始化const成员会导致什么问题。 Item5的测试题目: 1. 给定一个包含引用成员的类,询问是否可以进行拷贝赋值操作。 2. 编写一个类,其中包含const成员,测试默认拷贝赋值运算符是否被生成。 3. 解释为什么某些情况下编译器不会生成拷贝赋值运算符。 需要确保题目符合用户要求,不需要提供答案,只需要题目本身。同时,题目应具体,有针对性,能够通过测试用例验证对条款的理解。 现在组织这些题目,确保每个条款有2-3个题目,涵盖不同的方面。比如对于Item4,可以有一个编写正确构造函数的题目,一个分析问题的题目;对于Item5,可以有分析编译器生成函数的题目,以及需要用户自己声明或理解的题目。 最后检查是否符合用户的要求:用中文回答,结构清晰,测试用例题目不需要答案,正确使用LaTeX格式的数学表达式(不过这里可能不太需要,但需注意用户提到的系统级指令)。但用户的问题是关于C++的,可能不涉及数学公式,所以LaTeX部分可能用不上,但需要确保其他格式要求,如条款编号用粗体或适当强调。</think>**Effective C++ Item4-5 核心要点与测试用例题目** --- ### **Item4确定对象使用初始化** **核心内容**: 1. 区分“初始化”与“赋值”:成员变量应在构造函数初始化列表中初始化,而非在构造函数体内赋值。 2. 对于 `const` 成员、引用成员、类类型成员(无默认构造函数),必须使用初始化列表。 3. 初始化顺序仅由类中成员声明顺序决定,与初始化列表顺序无关。 **测试用例题目**: 1. 编写一个 `Student` 类,包含以下成员: - `const int id`(必须初始化) - `std::string& name`(引用类型) - `int age`(普通成员) 要求:正确实现构造函数,确保所有成员合法初始化。 2. 分析以下代码问题: ```cpp class Example { public: Example(int a) { m_a = a; // 此处为赋值而非初始化 m_b = 2 * a; } private: const int m_a; int m_b; }; ``` 指出编译错误原因并提供修改方案。 3. 以下类的初始化列表顺序与成员声明顺序不一致,是否存在风险?为什么? ```cpp class Resource { public: Resource(int x) : b(x), a(b) {} private: int a; int b; }; ``` --- ### **Item5:了解C++默默编写并调用哪些函数** **核心内容**: 1. 编译器会隐式生成默认构造函数、拷贝构造函数、拷贝赋值运算符(`operator=`)和析构函数。 2. 若类包含 `const` 成员、引用成员或基类拷贝赋值运算符不可访问,编译器可能拒绝生成拷贝赋值运算符。 3. 显式删除或定义某些函数(如 `=default`/`=delete`)可控制默认行为。 **测试用例题目**: 1. 给定以下类定义: ```cpp class Book { public: Book(const std::string& title) : title_ref(title) {} private: std::string& title_ref; // 引用成员 }; ``` 尝试编写代码 `Book b1("A"); Book b2 = b1;` 是否会编译失败?解释原因。 2. 设计一个 `NetworkConnection` 类,包含 `const int socket_fd` 成员: - 默认生成的拷贝赋值运算符是否合法? - 若需禁用拷贝,应如何实现? 3. 分析以下场景: ```cpp class Base { public: Base& operator=(const Base&) = delete; // 显式删除拷贝赋值 }; class Derived : public Base {}; ``` `Derived` 类的对象是否能使用默认生成的拷贝赋值运算符?为什么? --- 以上题目可用于验证对 Item4-5 的理解,重点考察初始化列表的必要性、编译器隐式生成函数的条件与限制。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值