C++基础(一些经常混淆的概念)

这篇博客主要是自己在看完C++ Primer Plus第六版后的一个笔记,如果大家想学C++,还是建议先看一下C++ Primer plus(这本主要是基础),看完这本书之后,才觉得很多东西要去学,千万不要别说精通C++,想精通C++,要学特别多。

在复习C++之前,一门高级语言是如何被计算机所识别的(即其识别的过程如下:)
C++基础(一些经常混淆的概念)_第1张图片

操作符重载

大多数运算符都可以通过成员和非成员函数进行重载,但是下列的运算符只能通过成员函数重载
符号 说明
= 赋值操作符
() 函数调用运算符
[] 下标运算符
-> 通过指针访问类成员的运算符

++a等这种只能通过非成员函数进行重载

不能重载的操作符
符号 说明
. 成员运算符
.* 成员指针运算符
? 条件运算符
:: 作用域运算符
sizeof sizeof运算符
typeid 一个RTTI运算符
const_cast 强制类型转换运算符
dynamic_cast 强制类型转换运算符
reinterpret_cast 强制类型转换运算符
static_cast 强制类型转换运算符

友元类型

  • 友元类
  • 友元成员函数
友元类
class TV
{
  public:
  friend class Remote; //类Remote可以访问类Tv的私有成员
  //.....
};
class Remote
{
  //....
};
友元成员函数
class Tv{
public:
friend void Remote::set_chan(Tv &t,int c);
//...
};
class remote
{
  //...
};

友元类几个注意点:
声明顺序(采用前向声明)
不要使用内联函数
要在类中声明哪些类是自己的友元类

C++ 函数返回效率问题

  • C++ 函数返回效率问题,如果函数返回对象将调用复制构造函数,而返回引用就不会,但是引用指向的对象应该在调用函数执行时候存在。如果返回的是局部变量,则不应按引用方式返回它,因为在被调用函数执行完毕时,局部对象将调用其析构函数。
  • const 成员变量一定要在执行构造函数之前初始化,即在创建对象时候进行初始化。c++ 提供了成员初始化列表,如下所示:
Queue::Queue(int qs):qsize(qs)
{
}

通常,初值可以是常量或是构造函数的参数列表中的参数,这种方法不限于初始化常量。只有构造函数可以使用这种初始化列表。对于const成员必须使用这个方法初始化,引用与const数据一样,只能在创建的时候进行初始化。使用成员初始化列表的效率更高。

C++继承:public,protected,private

  1. 公有继承(public)
    公有继承的特点是基类的公有成员和保护成员作为派生类的成员时,它们都保持原有的状态,而基类的私有成员仍然是私有的,不能被这个派生类的子类所访问。
  2. 私有继承(private)
    私有继承的特点是基类的公有成员和保护成员都作为派生类的私有成员,并且不能被这个派生类的子类所访问。
  3. 保护继承(protected)
    保护继承的特点是基类的所有公有成员和保护成员都成为派生类的保护成员,并且只能被它的派生类成员函数或友元访问,基类的私有成员仍然是私有的。

下面列出三种不同的继承方式的基类特性和派生类特性

public protected private
共有继承 public protected
保护继承 protected protected
私有继承 private private

1)基类成员对派生类都是:共有和保护的成员是可见的,私有的的成员是不可见。
2)基类成员对派生类的对象来说:要看基类的成员在派生类中变成了什么类型的成员。如:私有继承时,基类的共有成员和私有成员都变成了派生类中的私有成员,因此对于派生类中的对象来说基类的共有成员和私有成员就是不可见的

派生类和基类之间有一些特殊关系

  • 1.派生类对象可以使用基类的方法,条件是方法不是私有的

  • 2.基类指针可以在不进行显示转换的情况下指向派生类的对象;基类引用可以在不显示类型转换的情况下引用派生类的对象

然而 基类的指针和引用只能调用基类的方法。

公有继承不能建立has-a的关系,is-like-a的关系,以及 is-implemented-as-a(作为。。。。。来实现),比如使用数组来实现栈,但是从Array类派生出来Stack类是不合适的,最后也不能建立 uses-a的关系,例如计算机可以使用激光打印机,但是从Computer派生出来Printer类明显不合适。

由于既可以使用包含,也可以使用私有继承来实现has-a关系,大多数C++程序员倾向使用包含。首先,它容易理解。类申明包含表示被包含的类的显示命名对象,代码可以通过名称引用这些对象,而使用继承将关系更抽象。其次,继承会引发很多问题。可能要处理很多问题,如包含同名方法的独立的基类或共享祖先的独立基类。
然而,私有继承提供的特性确实比包含多。例如,假设类包含保护成员(可以是数据成员,也可以成员函数),则这样的成员在派生类是可以使用。但是在继承层次结构外是不能使用的。如果使用组合将这样的类包含在其中一个类中,则后者不是继承,而是位于继承结构之外的,因此不能访问保护成员。但是通过继承得到将是派生类。因此能访问保护成员

总之,通常,应使用包含来建立has-a的关系;如果新类需要访问原有类的保护成员,或需要重新定义虚函数,则应使用私有继承。

C++ 多态实现的途径

  • 1.在派生类重新定义基类的方法
  • 2.使用虚函数

如果方法是通过引用和指针而不是对象调用的,它将确定使用哪一种方法,如果没有使用关键字virtual,程序将根据引用类型和指针类型选择方法,如果使用virtual,程序将根据引用或指针指向的对象类型来选择方法。重新定义不会生成函数的两个重载版本,而是隐藏了基类的版本,方法在基类中被定义成虚函数之后,在派生类中将自动成为虚函数.
首先来看效率。为了使程序能够在运行阶段进行决策,必须采用一些方法来跟踪基类指针或引用的对象类型,这增加了额外的处理开销如果类不用作为基类,则不用需要动态联编,同样,如果派生类不重新定义基类任何方法,也不需要动态联编。编译器对非虚方法采用的是静态联编

总之,使用虚函数时,在内存和执行速度上方面都有一定的成本,包括:
+ 1.每个对象都将增大,增大量为存储地址的空间
+ 2.对于每个类,编译器都创建一个虚函数地址表(该表是一个数组)
+ 3.对于每个函数的调用,都需要执行一项额外的时间,即是到表中查找地址
+ 4.只有成员才能是虚函数

注意:纯虚函数的基类参数一定要跟派生类是一样的,但是虚函数可以不一样。

在下列情况下,将可以使用复制构造函数
  • 1.将新对象初始化为一个同类对象
  • 2.按值将对象传递给函数
  • 3.函数按值返回对象
  • 4.编译器生成临时对象

在私有继承中,在不进行显示类型转换的情况下,不能将指向派生类的引用或是指针赋值给基类的引用或是指针

你可能感兴趣的:(C++)