[面试珠玑]C++空类中的默认函数

2024-02-19 02:58

本文主要是介绍[面试珠玑]C++空类中的默认函数,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

参加面试的时候,面试官问到这个问题,我的回答:默认构造函数、默认析构函数、默认拷贝构造函数、默认赋值函数。现在回想起来感觉不对,就google,揭示一下这个看似简单的问题:

一个空的class在C++编译器处理过后就不再为空,编译器会自动地为我们声明一些member function,如果你写 


class A{}; 
编译器处理后,就相当于: 

class A
{ 
public: 
A();  //默认构造函数
A(const A&);  //拷贝构造函数
~A();  //析构函数
A& operator=(const A& rhs); 
A* operator&();  //取地址运算符
const A* operator&() const;
}; 

基本上符合我上文的回答,只是多了取地址运算符的两个函数。

这种回答对否?

其实对于这样的一个空类来说,是完全没有必要的,而编译器也不是这样做的。编译器的做法是:

只有你需要用到这些函数并且你又没有显示的声明这些函数的时候,编译器才会贴心的自动声明相应的函数。  

比如   
A   a;   
编译器就会根据上面的实例,给类A生成构造函数和析构函数。   
当使用   
A   b(b);   
编译器就会生成类A的拷贝构造函数。   
A   c;   
c   =   a;   
编译器生成赋值运算符函数   
A   &d   =   a;   
编译器生成取地址运算符函数。   
    
经过我们的分析可以这样理解:对于一个没有实例化的空类,编译器是不会给它生成任何函数的,当实例化一个空类后,编译器会根据需要生成相应的函数。这条理论同样适合非空类(只声明变量,而不声明函数)。


题外话,方便记住:

其中的默认拷贝赋值操作符只有在生成的代码合法并且有机会证明它有意义存在时才会生成。这就说明,如果你打算在一个“内含引用成员”或者“内含const成员”的类内支持赋值操作,就必须定义自己的默认拷贝赋值操作符。因为C++本身不允许引用改指不同的对象,也不允许更改const成员。

最后一种情况,当基类将自己的默认拷贝赋值操作符声明为private时,子类就不会产生自己的的默认拷贝赋值操作符。因为假如产生了这样的默认拷贝赋值操作符,它会试着去调用基类的默认拷贝赋值操作符去处理基类的部分,不幸的是,它没有权利。

你可以将拷贝构造函数或默认拷贝赋值操作符声明为private。这样明确声明一个成员函数,就阻止了编译器暗自创建的默认版本,而这些函数为private,使得可以成功阻止人们调用它。

上面的做法有一个隐患,因为类自身的member和friend还是可以调用这些private函数。有一个很刁钻的方法,“将成员函数声明为private而且故意不实现它们”,这样既阻止了默认函数的生成,而且如果你试着调用这些函数,就会得到一个链接错误。只声明,不定义,链接器报错。甚至在声明的时候,你连参数也不用写。

只要类里有指针变量就得自己写拷贝构造函数和赋值函数,但是你确定用不着这些函数时,可以把这些函数做private声明而不去实现它,这就防止了会有人去调用它们,也防止了编译器去生成它们。

如果没有自定义复制构造函数,则系统会创建默认的复制构造函数,但系统创建的默认复制构造函数只会执行“浅拷贝”,即将被拷贝对象的数据成员的值一一赋值给新创建的对象,若该类的数据成员中有指针成员,则会使得新的对象的指针所指向的地址与被拷贝对象的指针所指向的地址相同,delete该指针时则会导致两次重复delete而出错。

这篇关于[面试珠玑]C++空类中的默认函数的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/723297

相关文章

PyCharm如何设置新建文件默认为LF换行符

《PyCharm如何设置新建文件默认为LF换行符》:本文主要介绍PyCharm如何设置新建文件默认为LF换行符问题,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目录PyCharm设置新建文件默认为LF换行符设置换行符修改换行符总结PyCharm设置新建文件默认为LF

C++ 中的 if-constexpr语法和作用

《C++中的if-constexpr语法和作用》if-constexpr语法是C++17引入的新语法特性,也被称为常量if表达式或静态if(staticif),:本文主要介绍C++中的if-c... 目录1 if-constexpr 语法1.1 基本语法1.2 扩展说明1.2.1 条件表达式1.2.2 fa

Android Kotlin 高阶函数详解及其在协程中的应用小结

《AndroidKotlin高阶函数详解及其在协程中的应用小结》高阶函数是Kotlin中的一个重要特性,它能够将函数作为一等公民(First-ClassCitizen),使得代码更加简洁、灵活和可... 目录1. 引言2. 什么是高阶函数?3. 高阶函数的基础用法3.1 传递函数作为参数3.2 Lambda

C++中::SHCreateDirectoryEx函数使用方法

《C++中::SHCreateDirectoryEx函数使用方法》::SHCreateDirectoryEx用于创建多级目录,类似于mkdir-p命令,本文主要介绍了C++中::SHCreateDir... 目录1. 函数原型与依赖项2. 基本使用示例示例 1:创建单层目录示例 2:创建多级目录3. 关键注

C++从序列容器中删除元素的四种方法

《C++从序列容器中删除元素的四种方法》删除元素的方法在序列容器和关联容器之间是非常不同的,在序列容器中,vector和string是最常用的,但这里也会介绍deque和list以供全面了解,尽管在一... 目录一、简介二、移除给定位置的元素三、移除与某个值相等的元素3.1、序列容器vector、deque

C++常见容器获取头元素的方法大全

《C++常见容器获取头元素的方法大全》在C++编程中,容器是存储和管理数据集合的重要工具,不同的容器提供了不同的接口来访问和操作其中的元素,获取容器的头元素(即第一个元素)是常见的操作之一,本文将详细... 目录一、std::vector二、std::list三、std::deque四、std::forwa

C++字符串提取和分割的多种方法

《C++字符串提取和分割的多种方法》在C++编程中,字符串处理是一个常见的任务,尤其是在需要从字符串中提取特定数据时,本文将详细探讨如何使用C++标准库中的工具来提取和分割字符串,并分析不同方法的适用... 目录1. 字符串提取的基本方法1.1 使用 std::istringstream 和 >> 操作符示

C++原地删除有序数组重复项的N种方法

《C++原地删除有序数组重复项的N种方法》给定一个排序数组,你需要在原地删除重复出现的元素,使得每个元素只出现一次,返回移除后数组的新长度,不要使用额外的数组空间,你必须在原地修改输入数组并在使用O(... 目录一、问题二、问题分析三、算法实现四、问题变体:最多保留两次五、分析和代码实现5.1、问题分析5.

C++ 各种map特点对比分析

《C++各种map特点对比分析》文章比较了C++中不同类型的map(如std::map,std::unordered_map,std::multimap,std::unordered_multima... 目录特点比较C++ 示例代码 ​​​​​​代码解释特点比较1. std::map底层实现:基于红黑

C++中函数模板与类模板的简单使用及区别介绍

《C++中函数模板与类模板的简单使用及区别介绍》这篇文章介绍了C++中的模板机制,包括函数模板和类模板的概念、语法和实际应用,函数模板通过类型参数实现泛型操作,而类模板允许创建可处理多种数据类型的类,... 目录一、函数模板定义语法真实示例二、类模板三、关键区别四、注意事项 ‌在C++中,模板是实现泛型编程