EagleBear2002 的博客

这里必须根绝一切犹豫,这里任何怯懦都无济于事

C++ 高级程序设计-25-面向对象编程十大问题

构造函数

当类中未自主定义构造函数,编译器会提供默认构造函数,为什么?编译器会对一个空类做什么?

  1. 编译器只有在一定需要默认构造函数的时候,才去创建构造函数。
  2. 编译器会对一个空类生成这些函数:
1
2
3
4
5
6
7
8
9
class Empty {
// 编译器为空类提供的函数:
Empty(); // 默认构造函数
Empty(const Empty&); // 默认拷贝构造函数
~Empty(); // 默认析构函数
Empty& operator=(const Empty&); // 默认拷贝赋值函数
Empty *operator&(); // 默认重载取对象地址
const Empty *operator&() const; // 默认重载取常量对象地址
};

构造函数和析构函数

何时构造函数、析构函数被定义为 private?何时、如何使用友元、static 成员?

  1. private 的构造函数和析构函数常常用在某些设计模式下的情况,例如单例模式:构造函数的私有化的类的设计保证了其他类(包括其派生类)不能创建类的实例(单件模式)
  2. 使用方法:通过友元类对象的方法来完成创建、使用 static 方法完成创建

成员初始化表

为什么引入成员初始化表?为什么初始化表执行次序只与类数据成员的定义次序相关?

  1. 为了提高编译效率,减轻编译器负担
  2. 按照成员定义次序初始化,可以达到提高编译效率的目的
  3. 原则上的初始化顺序:就地初始化 > 构造函数的初始化列表 > 构造函数里的赋值(严格意义上不能成为初始化)
1
2
3
4
5
6
class CString {
char *p;
int size;
public:
CString(int x): size(x),p(new char[size]) {}
};

拷贝构造函数和赋值函数

为什么引入拷贝构造函数、赋值函数?

  1. 防止浅拷贝带来的问题,需要由程序员管理各种资源
  2. 拷贝构造函数和赋值函数可以提高效率

后期绑定

什么是后期绑定? C++ 如何实现虚函数?

  1. 运行时确定调用哪个函数的代码
  2. 通过在对象头部加入虚函数表来实现后期动态绑定

虚函数

何时使用虚函数?

  1. 当子类方法需要表现出不同行为的时候

继承方式

public 继承和 non-pablic 继承意味着什么?

non-public 继承在需要使使用 Base Class 中的 protected 成员,或重载 virtual function 时,同时不希望 Base Class 被客户代码使用。

public protected private
public 继承 public protected 不可见
protected 继承 protected protected 不可见
private 继承 private private 不可见

重载注意事项

为什么 =, (), [], -> 不能作为全局函数重载?

  1. 大体上来讲,C++ 一个类本身对这几个运算符就已经有了相应的解释了。
  2. 如果将这四种符号进行友元全局重载,则会出现一些二义性冲突

返回引用

什么时候成员函数能返回引用?

  1. 需要改变原有值
  2. 节省空间、提高效率、避免多余拷贝

内存分配方式的重载

什么时候、如何重载 newdelete

  1. 需要程序员自己来管理内存的时候(需要多次调用原有 new/delete 的时候,嫌慢)
  2. new 的重载可以有多个
1
2
3
void *operator new(size_t size, ...) {};
// 调用方式:
A *p = new (...) A;
  1. delete 的重载只能有一个。
1
2
void operator delete(void *p, size_t size);
// 第一个参数表示被撤销的对象地址,第二个参数可有可无,表示被撤销的参数的大小
  1. new/delete 重载之后,就不能再使用预定义的
  2. 重载的 new/delete 是静态成员,遵循类的访问控制,可继承
  3. 允许进行全局重载,但是不推荐使用全局重载