effective c++

探讨C++中的关键概念,如const、枚举、内联替代宏定义,拷贝构造与赋值的区别,模板与内联函数的应用,以及异常处理机制。深入解析C++语言联邦特性,类型传递效率,私有成员访问机制,以及类继承与多态的细节。

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

Widget W3 = W2; 调用copy constructor函数,非copy assignment函数
ab, 相当于函数调用operator(a,b)
const int operator* (const int& lhs, const int& rhs)

条款1:c++是语言联邦:c、object-oriented c++、template c++、STL
对内置类型,pass-by-value比pass-by-reference高效

条款2:以const, enum, inline替换#define
class专属常量
class Game {
static const int Num = 5; //常量声明式
}
优秀的编译器不会为"整数型const对象"设定存储空间, 除非创建pointer或reference指向该对象

#define CALL_MAX(a, b) f((a) > (b) ? (a) : (b))
int a=5, b=0;
CALL_MAX(++a, b); //a被累加2次
CALL_MAX(++a, b+10); //a被累加1次
template
inline void call_max(const T& a, const T& b) {…}
不会产生上述问题

条款24:
result = oneHalf2; 等效于 result = oneHalf.operator(2);

条款25:
1、bool A::sameCount(const A &a)是类本身的一个成员函数。
“私有的成员变量”的意思就是只能被自身访问的成员,这里的sameCount就是自身的成员函数,所以能够访问自身的任何类型的成员变量。
2、类的访问权限作用在类上,不是作用在对象上,所以虽然可能参数中的const A &a是另一个对象,但是在这里使用的是类的权限(类的成员函数),所以就可以访问。
copy构造函数,不可避免地用到另一个对象的private成员的,“访问权限作用于类,而非对象”这个机制确实是必须的。
条款26:尽可能延后变量定义式的出现
c风格转型 (T) expression
函数风格转型T(expression)
Derived d;
Base pb = &d
有可能有个偏移量offset在运行期施加于Derived
指针上,从而取得正确的Base指针
单个对象可能有一个以上的地址(Base
指向它或者Derived指向它)
class SpecialWindow
Window::onResize(); //调用Window::onResize于
this上
条款27:尽可能隔离转型运算,将它隐藏在函数内
条款28:避免返回handles指向object内部
条款29:当异常被抛出时,不泄漏任何资源、不允许数据败坏
异常安全函数:基本型、强烈型、不抛异常型
条款30:inline函数和template一般置于头文件内,因为在编译过程中inlining。如果有个异常在对象构造期间被抛出,构造好的那部分会被自动销毁
条款31:当编译器看到Person p(params);的定义时,编译器必须分配足够空间以放置Person,而Person *p或&p时不需要,只需要知道class Person的声明即可。
为声明和定义式提供不同的头文件,程序头文件完全且"仅有声明式"
相依于声明式,非定义式,使得编译依存最小
条款33:派生类一般无法继承base类的重载函数
cpp为了防止derived class附带地从base class继承重载函数,所以derived class的作用域会屏蔽base class作用域的名字
为了避免这种遮掩,可以继承重载函数,使用using Base::mf1;
条款34:derived class只继承接口:pure virtual function, 调用方式Base::func
继承接口和实现,可override:virtual function
继承接口和实现,不可override: non-virtual fun, 不应该在derived class中重新定义
条款35:derived class可重新定义base的private func
条款36:non-virtual函数静态绑定,derived class不应该重新定义non-virtual函数
条款37:virtual func动态绑定,而缺省参数值静态绑定
这是为了运行速度和编译器的实现复杂度而作的一种折中

条款52:placement new是operator new的重载版本
operator new的参数只有size_t
有其他参数的都是placement new,最常用的placement new是
void *operator new(new size_t, void *pMem) throw()
调用方式 *pw = new (std::cerr) Widget;
delete pw,对指针施行delete调用正常的operator delete,
placement delete只在’placenment new构造函数发生异常’时才被调用

more effective c++:
条款3:数组不支持多态,因为数组以静态类型的大小确定步长
cpp prefer list/vector等容器操作array

条款4: operator delete [] (rawMemory)
删除不以new operator获得的指针,结果没有定义
条款5:隐式转换(单一参数的constructor和隐式类型转换操作符)
条款7:函数调用语句,所有参数都必须评估完成

条款8:operator delete只释放operator new分配的内存
因为缺省版本的operator new是一种通用型的内存分配器,它必须可以分配任意大小的内存块。同样,operator delete也要可以释放任意大小的内存块。operator delete想弄清它要释放的内存有多大,就必须知道当初operator new分配的内存有多大。有一种常用的方法可以让operator new来告诉operator delete当初分配的内存大小是多少,就是在它所返回的内存里预先附带一些额外信息,用来指明被分配的内存块的大小。
条款9:局部对象总是在函数结束时被析构,即使函数是遇到exception结束
条款11:异常时在栈展开过程中会销毁局部对象,析构函数又发生异常时,会直接调用terminate函数
terminate被调用的情况:
1 当发送一个异常,并且构造函数产生异常
2 当发送一个异常,或者析构函数产生异常
3 一个静态对象的构造或者析构发送一个异常
4 以atexit注册的函数发生异常的时候
5 自定义一个异常,但是实际上没有异常产生的时候
6 调用缺省的unexcepted()函数时候
条款12:exception时对象总是被复制, 而且复制的是静态类型
catch (Widget& w) {throw;}
如果catch的是SpecialWidget,则向上throw原来的SpecialWidget,不需要产生新的object
条款13:catch by pointer:object删除问题
catch by value: 复制二次效率问题、slice问题(调用非预期virtual function)
1)不写异常说明,表示可以抛出任何异常;
2)空异常说明,throw (),表示不会抛出任何异常。

条款20:C++真正的临时对象是不可见的匿名对象,不会出现在你的源码中,但是程序在运行时确实生成了这样的对象.
c++禁止为non-const reference参数产生临时对象,因为临时对象被更改,而不是期望的原变量被修改

条款21: 每个重载操作符至少有一个参数是自定义class,不然会改变内置类型操作符的含义

条款25:new operator返回指针,delete 删除指针
当derived class重新定义虚函数时,不一定非得与base class中虚函数返回类型相同,可以指向原本返回类型的扩展类

条款26:带有private constructor的class不得被继承
class Person{…};
class Student:private Person{…};
void eat(const Person &p);
Person p;
Student s;
eat§;//正确
eat(s);//错误

再看看Effective C++的说法:
如果classes之间的继承关系是private,编译器不会自动将一个deirved class对象转换为一个base class对象。
private继承意味着implemented-in-terms-of(根据某物实现出)。如果你让class D以private继承class B,你的用意是为了采用class B内已经备妥的某些特性,不是因为B对象和D对象存在有任何观念上的关系。private继承纯粹是一种实现技术,意味着只有实现部分被继承,接口部分应该略去。如果D以private形式继承B,意思是D对象根据B对象实现而得,private继承在软件设计层面上没有意义,其意义只及于软件实现层面。

1)派生类对象d是无法访问基类的任一成员函数的(包括public成员函数),因为这是private继承
2)派生类本身是能访问基类的public 和protected成员的
private表现出的关系是“根据某物实现出”,它继承的是实现而非接口
可以使用using访问基类中的名字

在《c++primer第四版中文》p572页的注解中指出:“派生类可以恢复继承成员的访问级别,但不能使访问级别比基类中原来指定的更严格或更宽松”。亲自用visual studio 2008试验了一下,怀疑书上观点有误,特别写出和大家交流,以找出正确答案。
在基类中的private成员,不能在派生类中任何地方用using声明。
在基类中的protected成员,可以在派生类中任何地方用using声明。当在public下声明时,在类定义体外部,可以用派生类对象访问该成员,但不能用基类对象访问该成员;当在protected下声明时,该成员可以被继续派生下去;当在private下声明时,对于派生类定义体外部来说,该成员是派生类的私有成员。
在基类中的public成员,可以在派生类中任何地方用using声明。

using Base::pub_var; 修改访问层级
protected 成员:
1). 像private成员,不能被类的用户访问
2). 像public成员,可被类的派生类访问
派生类只能通过派生类object访问基类的protected成员,不能访问基类object的protected成员
条款27:多重继承或virtual base情况下,object有多个地址,
通过dynamic_cast<const void *>(*this)可将其转换为object的内存起始处
条款28:pt->display(); 编译器将它解读为(pt.operator->()) -> display()
template functions暗自实例化
SmartPtr和SmartPtr是两种不同的类型
条款34:static class/全局object/namespace内的object,文件范围内的object,其constructor总是在main之前执行
动态分配内存:c++ new/delete, c 是malloc/free

基于数据挖掘的音乐推荐系统设计与实现 需要一个代码说明,不需要论文 采用python语言,django框架,mysql数据库开发 编程环境:pycharm,mysql8.0 系统分为前台+后台模式开发 网站前台: 用户注册, 登录 搜索音乐,音乐欣赏(可以在线进行播放) 用户登陆时选择相关感兴趣的音乐风格 音乐收藏 音乐推荐算法:(重点) 本课题需要大量用户行为(如播放记录、收藏列表)、音乐特征(如音频特征、歌曲元数据)等数据 (1)根据用户之间相似性或关联性,给一个用户推荐与其相似或有关联的其他用户所感兴趣的音乐; (2)根据音乐之间的相似性或关联性,给一个用户推荐与其感兴趣的音乐相似或有关联的其他音乐。 基于用户的推荐和基于物品的推荐 其中基于用户的推荐是基于用户的相似度找出相似相似用户,然后向目标用户推荐其相似用户喜欢的东西(和你类似的人也喜欢**东西); 而基于物品的推荐是基于物品的相似度找出相似的物品做推荐(喜欢该音乐的人还喜欢了**音乐); 管理员 管理员信息管理 注册用户管理,审核 音乐爬虫(爬虫方式爬取网站音乐数据) 音乐信息管理(上传歌曲MP3,以便前台播放) 音乐收藏管理 用户 用户资料修改 我的音乐收藏 完整前后端源码,部署后可正常运行! 环境说明 开发语言:python后端 python版本:3.7 数据库:mysql 5.7+ 数据库工具:Navicat11+ 开发软件:pycharm
MPU6050是一款广泛应用在无人机、机器人和运动设备中的六轴姿态传感器,它集成了三轴陀螺仪和三轴加速度计。这款传感器能够实时监测并提供设备的角速度和线性加速度数据,对于理解物体的动态运动状态至关重要。在Arduino平台上,通过特定的库文件可以方便地与MPU6050进行通信,获取并解析传感器数据。 `MPU6050.cpp`和`MPU6050.h`是Arduino库的关键组成部分。`MPU6050.h`是头文件,包含了定义传感器接口和函数声明。它定义了类`MPU6050`,该类包含了初始化传感器、读取数据等方法。例如,`begin()`函数用于设置传感器的工作模式和I2C地址,`getAcceleration()`和`getGyroscope()`则分别用于获取加速度和角速度数据。 在Arduino项目中,首先需要包含`MPU6050.h`头文件,然后创建`MPU6050`对象,并调用`begin()`函数初始化传感器。之后,可以通过循环调用`getAcceleration()`和`getGyroscope()`来不断更新传感器读数。为了处理这些原始数据,通常还需要进行校准和滤波,以消除噪声和漂移。 I2C通信协议是MPU6050与Arduino交互的基础,它是一种低引脚数的串行通信协议,允许多个设备共享一对数据线。Arduino板上的Wire库提供了I2C通信的底层支持,使得用户无需深入了解通信细节,就能方便地与MPU6050交互。 MPU6050传感器的数据包括加速度(X、Y、Z轴)和角速度(同样为X、Y、Z轴)。加速度数据可以用来计算物体的静态位置和动态运动,而角速度数据则能反映物体转动的速度。结合这两个数据,可以进一步计算出物体的姿态(如角度和角速度变化)。 在嵌入式开发领域,特别是使用STM32微控制器时,也可以找到类似的库来驱动MPU6050。STM32通常具有更强大的处理能力和更多的GPIO口,可以实现更复杂的控制算法。然而,基本的传感器操作流程和数据处理原理与Arduino平台相似。 在实际应用中,除了基本的传感器读取,还可能涉及到温度补偿、低功耗模式设置、DMP(数字运动处理器)功能的利用等高级特性。DMP可以帮助处理传感器数据,实现更高级的运动估计,减轻主控制器的计算负担。 MPU6050是一个强大的六轴传感器,广泛应用于各种需要实时运动追踪的项目中。通过 Arduino 或 STM32 的库文件,开发者可以轻松地与传感器交互,获取并处理数据,实现各种创新应用。博客和其他开源资源是学习和解决问题的重要途径,通过这些资源,开发者可以获得关于MPU6050的详细信息和实践指南
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值