C/C++你必须知道的小知识(26)

120 阅读5分钟

持续创作,加速成长!这是我参与「掘金日新计划 · 6 月更文挑战」的第26天,点击查看活动详情


1.3.31 说说什么是虚基类,可否被实例化?

参考回答

  1. 在被继承的类前面加上virtual关键字,这时被继承的类称为虚基类,代码如下:

    class A
    class B1:public virtual A;
    class B2:public virtual A;
    class D:public B1,public B2;
    
  2. 虚继承的类可以被实例化,举例如下:

    class Animal {/* ... */ };
    
    class Tiger : virtual public Animal { /* ... */ };
    
    class Lion : virtual public Animal { /* ... */ }
    
    int main( )
    {
    Liger lg ;
    
    /*既然我们已经在Tiger和Lion类的定义中声明了"virtual"关键字,于是下面的代码编译OK */
    
    int weight = lg.getWeight();
    }
    

1.3.32 简述一下拷贝赋值和移动赋值?

参考回答

  1. 拷贝赋值是通过拷贝构造函数来赋值,在创建对象时,使用同一类中之前创建的对象来初始化新创建的对象。

  2. 移动赋值是通过移动构造函数来赋值,二者的主要区别在于

    1)拷贝构造函数的形参是一个左值引用,而移动构造函数的形参是一个右值引用;

    2)拷贝构造函数完成的是整个对象或变量的拷贝,而移动构造函数是生成一个指针指向源对象或变量的地址,接管源对象的内存,相对于大量数据的拷贝节省时间和内存空间。

1.3.33仿函数了解吗?有什么作用

参考回答

  1. 仿函数(functor)又称为函数对象(function object)是一个能行使函数功能的类。仿函数的语法几乎和我们普通的函数调用一样,不过作为仿函数的类,都必须重载operator()运算符,举个例子:
 class Func{
     public:
         void operator() (const string& str) const {
             cout<<str<<endl;
         }
 };
 Func myFunc;
 myFunc("helloworld!");
>>>helloworld!
  1. 仿函数既能想普通函数一样传入给定数量的参数,还能存储或者处理更多我们需要的有用信息。我们可以举个例子:

    假设有一个vector<string>,你的任务是统计长度小于5的string的个数,如果使用count_if函数的话,你的代码可能长成这样:

      bool LengthIsLessThanFive(const string& str) {
           return str.length()<5;    
      }
      int res=count_if(vec.begin(), vec.end(), LengthIsLessThanFive);
    

    其中count_if函数的第三个参数是一个函数指针,返回一个bool类型的值。一般的,如果需要将特定的阈值长度也传入的话,我们可能将函数写成这样:

      bool LenthIsLessThan(const string& str, int len) {
          return str.length()<len;
      }
    

    这个函数看起来比前面一个版本更具有一般性,但是他不能满足count_if函数的参数要求:count_if要求的是unary function(仅带有一个参数)作为它的最后一个参数。如果我们使用仿函数,是不是就豁然开朗了呢:

      class ShorterThan {
          public:
              explicit ShorterThan(int maxLength) : length(maxLength) {}
              bool operator() (const string& str) const {
                  return str.length() < length;
              }
          private:
              const int length;
      };
    

1.3.34 C++ 中哪些函数不能被声明为虚函数?

参考回答

常见的不不能声明为虚函数的有:普通函数(非成员函数),静态成员函数,内联成员函数,构造函数,友元函数。

  1. 为什么C++不支持普通函数为虚函数?

    普通函数(非成员函数)只能被overload,不能被override,声明为虚函数也没有什么意思,因此编译器会在编译时绑定函数。

  2. 为什么C++不支持构造函数为虚函数?

    这个原因很简单,主要是从语义上考虑,所以不支持。因为构造函数本来就是为了明确初始化对象成员才产生的,然而virtual function主要是为了再不完全了解细节的情况下也能正确处理对象。另外,virtual函数是在不同类型的对象产生不同的动作,现在对象还没有产生,如何使用virtual函数来完成你想完成的动作。(这不就是典型的悖论)

    构造函数用来创建一个新的对象,而虚函数的运行是建立在对象的基础上,在构造函数执行时,对象尚未形成,所以不能将构造函数定义为虚函数

  3. 为什么C++不支持内联成员函数为虚函数?

    其实很简单,那内联函数就是为了在代码中直接展开,减少函数调用花费的代价,虚函数是为了在继承后对象能够准确的执行自己的动作,这是不可能统一的。(再说了,inline函数在编译时被展开,虚函数在运行时才能动态的绑定函数

    内联函数是在编译时期展开,而虚函数的特性是运行时才动态联编,所以两者矛盾,不能定义内联函数为虚函数

  4. 为什么C++不支持静态成员函数为虚函数?

    这也很简单,静态成员函数对于每个类来说只有一份代码,所有的对象都共享这一份代码,他也没有要动态绑定的必要性。

    静态成员函数属于一个类而非某一对象,没有this指针,它无法进行对象的判别

  5. 为什么C++不支持友元函数为虚函数?

    因为C++不支持友元函数的继承,对于没有继承特性的函数没有虚函数的说法。