📜  C++ 常见面试问题

📅  最后修改于: 2020-10-21 05:50:01             🧑  作者: Mango

C++面试题

下面列出了最常见的C++面试问题和答案。

1)什么是C++?

C++是由Bjarne Stroustrup创建的一种面向对象的编程语言。它于1985年发布。

C++是C的超集,主要增加了C语言中的类。

最初,Stroustrup将新语言称为“带有类的C”。但是,一段时间后,名称更改为C++。 C++的思想来自C增量运算符++。

2)C++有哪些优势?

C++不仅维护了C语言的所有方面,还简化了内存管理并添加了以下功能:

  • C++是一种高度可移植的语言,这意味着使用C++语言开发的软件可以在任何平台上运行。
  • C++是一种面向对象的编程语言,其中包含诸如类,对象,继承,多态性,抽象之类的概念。
  • C++具有继承的概念。通过继承,可以消除冗余代码,并可以重用现有的类。
  • 数据隐藏可以帮助程序员构建安全的程序,以使程序不会受到入侵者的攻击。
  • 消息传递是一种用于对象之间通信的技术。
  • C++包含丰富的函数库。

3)C和C++有什么区别?

以下是C和C++之间的区别:

C C++
C language was developed by Dennis Ritchie. C++ language was developed by Bjarne Stroustrup.
C is a structured programming language. C++ supports both structural and object-oriented programming language.
C is a subset of C++. C++ is a superset of C.
In C language, data and functions are the free entities. In the C++ language, both data and functions are encapsulated together in the form of a project.
C does not support the data hiding. Therefore, the data can be used by the outside world. C++ supports data hiding. Therefore, the data cannot be accessed by the outside world.
C supports neither function nor operator overloading. C++ supports both function and operator overloading.
In C, the function cannot be implemented inside the structures. In the C++, the function can be implemented inside the structures.
Reference variables are not supported in C language. C++ supports the reference variables.
C language does not support the virtual and friend functions. C++ supports both virtual and friend functions.
In C, scanf() and printf() are mainly used for input/output. C++ mainly uses stream cin and cout to perform input and output operations.

4)引用和指针有什么区别?

以下是引用和指针之间的区别:

Reference Pointer
Reference behaves like an alias for an existing variable, i.e., it is a temporary variable. The pointer is a variable which stores the address of a variable.
Reference variable does not require any indirection operator to access the value. A reference variable can be used directly to access the value. Pointer variable requires an indirection operator to access the value of a variable.
Once the reference variable is assigned, then it cannot be reassigned with different address values. The pointer variable is an independent variable means that it can be reassigned to point to different objects.
A null value cannot be assigned to the reference variable. A null value can be assigned to the reference variable.
It is necessary to initialize the variable at the time of declaration. It is not necessary to initialize the variable at the time of declaration.

5)什么是课程?

该类是用户定义的数据类型。该类用关键字class声明。该类包含数据成员,其成员函数由三个修饰符定义的成员函数是私有,公共和受保护的。该类定义事物类别的类型定义。它定义了一个数据类型,但没有定义数据,仅指定了数据结构。

您可以从一个类中创建N个对象。

6)C++中的各种OOP概念是什么?

C++中的各种OOPS概念是:

  • 类:

该类是用户定义的数据类型,用于定义其属性和功能。例如,人类是一类。人的身体部位就是其属性,身体部位所执行的动作称为功能。该类不占用任何内存空间。因此,可以说类是数据的唯一逻辑表示。

声明类的语法:

class student
{
//data members;
//Member functions
}
  • 目的:

对象是运行时实体。对象是类的实例。一个对象可以代表一个人,一个地方或任何其他项目。一个对象可以同时作用于数据成员和成员函数。该类不占用任何内存空间。使用new关键字创建对象时,将为堆中的变量分配空间,并且起始地址存储在堆栈存储器中。当创建没有新关键字的对象时,则不会在堆内存中分配空间,并且该对象在堆栈中包含空值。

class Student
{
//data members;
//Member functions
}

声明对象的语法:

Student s = new Student();
  • 遗产:

继承提供了可重用性。可重用性意味着可以使用现有类的功能。它消除了代码的冗余。继承是从旧类派生新类的技术。旧的类称为基类,新的类称为派生类。

句法

class derived_class :: visibility-mode base_class; 

注意:可见性模式可以是公共,私有,受保护的。

  • 封装形式:

封装是一种将数据成员和成员函数包装在单个单元中的技术。它将数据绑定到一个类中,并且没有外部方法可以访问该数据。如果数据成员是私有的,则成员函数只能访问数据。

  • 抽象:

抽象是仅显示基本细节而不表示实现细节的技术。如果成员是用public关键字定义的,则这些成员也可以在外部访问。如果成员是使用private关键字定义的,则外部方法无法访问这些成员。

  • 数据绑定:

数据绑定是绑定应用程序UI和业务逻辑的过程。业务逻辑中的任何更改将直接反映到应用程序UI。

  • 多态性:

多态性是指多种形式。具有相同的名称,但具有不同功能的多个函数多态性手段。多态性有两种类型:

  • 静态多态性也称为早期绑定。
  • 动态多态性也称为后期绑定。

7)C++中的多态性有哪些不同类型?

多态:多态是指多种形式。这意味着具有相同函数的名称,但具有不同功能的多个函数。

多态性有两种类型:

  • 运行时多态

运行时多态也称为动态多态。函数覆盖是运行时多态性的一个示例。函数覆盖意味着子类包含父类中已经存在的方法。因此,子类将覆盖父类的方法。在重写函数的情况下,父类和子类都包含具有不同定义的相同函数。在运行时确定对函数的调用称为运行时多态。

让我们通过一个例子来理解这一点:

#include 
using namespace std;
class Base
{
    public:
    virtual void show()
    {
        cout<<"javaTpoint";
     }
};
class Derived:public Base
{
    public:
    void show()
    {
        cout<<"javaTpoint tutorial";
    }
};

int main()
{
    Base* b;
    Derived d;
    b=&d;
    b->show();
                return 0;
}

输出:

javaTpoint tutorial
  • 编译时多态

编译时多态也称为静态多态。在编译时实现的多态被称为编译时多态。方法重载是编译时多态性的一个示例。

方法重载:方法重载是一种技术,它可以让你有一个以上的函数具有相同函数的名称,但具有不同的功能。

方法重载可能基于以下原因:

  • 重载函数的返回类型。
  • 传递给函数的参数类型。
  • 传递给函数的参数数量。

让我们通过一个例子来理解这一点:

#include 
using namespace std;
class Multiply
{
   public:
   int mul(int a,int b)
   {
       return(a*b);
   }
   int mul(int a,int b,int c)
   {
       return(a*b*c);
  }
 };
int main()
{
    Multiply multi;
    int res1,res2;
    res1=multi.mul(2,3);
    res2=multi.mul(2,3,4);
    cout<<"\n";
    cout<

输出:

6
24
  • 在上面的示例中,mul()是带有不同数量参数的重载函数。

8)在C++中定义名称空间。

  • 命名空间是代码的逻辑划分,旨在停止命名冲突。
  • 命名空间定义了声明诸如变量,类,函数之类的标识符的范围。
  • 在C++中使用名称空间的主要目的是消除歧义。当不同的任务以相同的名称发生时,会发生歧义。
  • 例如:如果存在两个具有相同名称的函数,例如add()。为了避免这种歧义,请使用名称空间。函数在不同的名称空间中声明。
  • C++由标准命名空间(即std)组成,其中包含内置的类和函数。因此,通过使用语句“ using namespace std;”在我们的程序中包括名称空间“ std”。
  • 命名空间的语法:
namespace namespace_name
{
 //body of namespace;
}

访问名称空间变量的语法:

namespace_name::member_name;

让我们通过一个例子来理解这一点:

#include 
using namespace std;
namespace addition
{
    int a=5;
    int b=5;
    int add()
    {
        return(a+b);
    }
}

int main() {
int result;
result=addition::add();
cout<

输出:

10

9)在C++中定义令牌。

C++中的令牌可以是关键字,标识符,字面量,常量和符号。

10)谁是C++的创造者?

Bjarne Stroustrup。

11)指针可以进行哪些操作?

以下是可以对指针执行的操作:

  • 增加或减少指针:增加指针意味着我们可以将指针增加其指向的数据类型的大小。

增量指针有两种类型:

1.预递增指针:预递增运算符将操作数递增1,表达式的值成为递增后的结果值。假设ptr是一个指针,则预递增指针表示为++ ptr。

让我们通过一个例子来理解这一点:

#include 
using namespace std;
int main()
{
int a[5]={1,2,3,4,5};
int *ptr;
ptr=&a[0];
cout<<"Value of *ptr is : "<<*ptr<<"\n";
cout<<"Value of *++ptr : "<<*++ptr;
return 0;
}

输出:

Value of *ptr is : 1
Value of *++ptr : 2

2.后递增指针:后递增运算符将操作数递增1,但是表达式的值将是操作数的值,而不是操作数的递增值。假设ptr是一个指针,则后递增指针表示为ptr ++。

让我们通过一个例子来理解这一点:

#include 
using namespace std;
int main()
{
int a[5]={1,2,3,4,5};
int *ptr;
ptr=&a[0];
cout<<"Value of *ptr is : "<<*ptr<<"\n";
cout<<"Value of *ptr++ : "<<*ptr++;
return 0;
}

输出:

Value of *ptr is : 1
Value of *ptr++ : 1
  • 从另一个指针减去一个指针:减去两个指向数组成员的指针时,将返回两个成员之间存在的元素数。

12)定义“ std”。

Std是C++中使用的默认名称空间标准。

13)哪种编程语言的不令人满意的性能导致了C++的发现?

发现C++是为了应对C的缺点。

14)delete []与delete有何不同?

Delete用于释放一个内存单元,delete []用于释放数组。

15)C++中STL的完整形式是什么?

STL代表标准模板库。

16)什么是物体?

对象是类的实例。一个类为对象提供了一个蓝图。因此,您可以从类创建对象。类的对象的声明与我们声明基本类型的变量的声明相同。

17)什么是C++访问说明符?

访问说明符用于定义如何在类外部访问函数和变量。

有三种类型的访问说明符:

  • 私有:声明为私有的函数和变量只能在同一类中访问,而不能在声明的类之外访问。
  • Public :可以在任何地方访问在public下声明的函数和变量。
  • 受保护的:声明为受保护的函数和变量只能在子类之外的类之外访问。该说明符通常用于继承。

18)什么是面向对象编程(OOP)?

OOP是一种提供许多概念的方法或范式。面向对象编程的基本概念如下:

类和对象:类用于指定数据的结构。它们定义数据类型。您可以从一个类中创建任意数量的对象。对象是类的实例。

封装:封装是一种将数据和关联的操作绑定在一起,从而将数据隐藏在外部世界中的机制。封装也称为数据隐藏。在C++中,它是使用访问说明符(即公共,私有和受保护的)来实现的。

抽象:抽象用于隐藏内部实现,并仅向外部世界显示必要的细节。数据抽象是使用C++中的接口和抽象类实现的。

有些人对封装和抽象感到困惑,但是他们都是不同的。

继承:继承用于将一个类的属性继承到另一个类。它可以帮助您用另一类来定义一个类。

19)数组和列表之间有什么区别?

  • 数组是同质元素的集合,而列表是异质元素的集合。
  • 数组内存分配是静态且连续的,而列表内存分配是动态且随机的。
  • 在Array中,用户无需跟踪下一个内存分配,而在列表中,用户必须跟踪下一个分配内存的位置。

20)new()和malloc()有什么区别?

  • new()是预处理器,而malloc()是函数。
  • 使用“ new”时不需要分配内存,但是在malloc()中必须使用sizeof()。
  • “ new”将新内存初始化为0,而malloc()在新分配的内存位置中给出随机值。
  • new()运算符分配内存并为对象初始化调用构造函数,而malloc()函数分配内存,但不为对象初始化调用构造函数。
  • new()运算符比malloc()函数快,因为运算符比函数快。

21)从DLL导出函数的方法有哪些?

有两种方法:

  • 通过使用DLL的类型库。
  • 从DLL实例中引用该函数。

22)定义朋友函数。

朋友函数充当班级的朋友。它可以访问该类的私有成员和受保护成员。朋友函数不是该类的成员,但是必须在类定义中列出。非成员函数无法访问该类的私有数据。有时,非成员函数必须访问数据。朋友函数是非成员函数,并且具有访问类的私有数据的能力。

为了使外部函数对类友好,我们需要将函数声明为类的朋友,如下所示:

class sample
{
   // data members;
 public:
friend void abc(void);
};

以下是朋友函数的特征:

  • 朋友函数不在其已声明的类的范围内。
  • 由于它不在类的范围内,因此不能通过使用类的对象来调用它。因此,友元函数可以调用像一个正常的函数。
  • 朋友函数无法直接访问私有成员,它必须在每个成员名称中使用对象名称和点运算符。
  • Friend函数使用对象作为参数。

让我们通过一个例子来理解这一点:

#include 
using namespace std;
class Addition
{
 int a=5;
 int b=6;
 public:
 friend int add(Addition a1)
 {
     return(a1.a+a1.b);
 }
};
int main()
{
int result;
Addition a1;
 result=add(a1);
 cout<

输出:

11

23)什么是虚函数?

  • 虚函数用于替换基类提供的实现。只要有问题的对象实际上是派生类的,就总是调用替换,即使该对象是由基本指针而不是派生指针访问的。
  • 虚函数是存在于基类中并由派生类重新定义的成员函数。
  • 当我们在基类和派生类中使用相同的函数名称时,基类中的函数用关键字virtual声明。
  • 将函数设为虚拟时,C++会在运行时根据基类指针所指向的对象的类型来确定要调用的函数。因此,通过使基类指针指向不同的对象,我们可以执行虚拟函数的不同版本。

虚函数规则:

  • 虚函数应该是某个类的成员。
  • 虚函数不能是静态成员。
  • 通过使用对象指针来调用虚函数。
  • 它可以是另一个班级的朋友。
  • C++不包含虚拟构造函数,但可以具有虚拟析构函数。

24)什么时候应该使用多重继承?

您可以通过三种方式回答此问题:

  • 决不
  • 很少
  • 如果发现问题域无法通过其他任何方式准确建模。

25)什么是析构函数?

析构函数用于删除对象分配的任何额外资源。对象超出范围后,将自动调用析构函数。

破坏者规则:

  • 析构函数的名称与类名称相同,并且以波浪号开头。
  • 它不包含任何参数,也没有返回类型。

26)什么是溢出错误?

这是一种算术错误。当算术运算的结果大于系统提供的实际空间时,就会发生这种情况。

27)什么是超载?

  • 当单个对象以多种方式运行时,称为重载。单个对象具有相同的名称,但是它提供相同函数的不同版本。
  • C++可以帮助您为同一范围内的函数名或运算符指定多个定义。分别称为函数重载和运算符重载。
  • 重载有两种类型:

1.运算符重载:运算符重载是一种编译时多态性,其中标准运算符被重载以为其提供用户定义的定义。例如,’+’运算符被重载以对int,float等数据类型执行加法运算。

运算符重载可以通过以下功能实现:

  • 会员函数
  • 非会员函数
  • 朋友函数

运算符重载的语法:

Return_type classname :: Operator Operator_symbol(argument_list)
{
      // body_statements;
}

2.函数重载:函数重载也是一种编译时多态性,可以定义具有相同名称的一系列函数。该函数将根据函数调用中的参数列表执行不同的操作。要调用的函数取决于参数数量和参数列表中参数的类型。

28)什么是函数替代?

如果您将一个类继承到派生类中,并在派生类中再次为基类的函数之一提供定义,则此函数称为覆盖函数,该机制称为函数覆盖。

29)什么是虚拟继承?

使用虚拟继承,即使对象在层次结构中出现多个,您也可以仅为每个对象创建一个副本。

30)什么是构造函数?

构造函数是一种初始化对象的特殊方法。其名称必须与类名称相同。

31)“删除”运算符的目的是什么?

“删除”运算符用于释放“新”运算符创建的动态内存。

32)解释这个指针?

该指针保存当前对象的地址。

33)范围解析运算符做什么?

范围解析运算符(::)用于在类外部定义成员函数。

34)delete和delete []有什么区别?

Delete []用于释放使用new []分配的已分配内存的数组,而delete用于释放使用new分配的一块内存。

35)什么是纯虚函数?

纯虚函数是不包含任何定义的虚函数。正常函数之前带有关键字virtual。纯虚函数以0结尾。

纯虚函数的语法:

virtual void abc()=0;   //pure virtual function.

让我们通过一个例子来理解这一点:

#include
using namespace std;
class Base
{
    public:
    virtual void show()=0;
};

class Derived:public Base
{
    public:
    void show()
    {
        cout<<"javaTpoint";
    }
};
int main()
{
    Base* b;
    Derived d;
    b=&d;
    b->show();
    return 0;
}

输出:

javaTpoint

36)struct和class有什么区别?

Structures class
A structure is a user-defined data type which contains variables of dissimilar data types. The class is a user-defined data type which contains member variables and member functions.
The variables of a structure are stored in the stack memory. The variables of a class are stored in the heap memory.
We cannot initialize the variables directly. We can initialize the member variables directly.
If access specifier is not specified, then by default the access specifier of the variable is “public”. If access specifier is not specified, then by default the access specifier of a variable is “private”.
The instance of a structure is a “structure variable”.
Declaration of a structure:
struct structure_name
{
   // body of structure;
} ;
Declaration of class:
class class_name
{
   // body of class;
} 
A structure is declared by using a struct keyword. The class is declared by using a class keyword.
The structure does not support the inheritance. The class supports the concept of inheritance.
The type of a structure is a value type. The type of a class is a reference type.

37)什么是课程模板?

类模板用于创建一系列类和函数。例如,我们可以创建一个数组类的模板,这将使我们能够创建各种类型的数组,例如int,float,char等。类似地,我们可以为一个函数创建一个模板,假设我们有一个函数add (),然后我们可以创建add()的多个版本。

类模板的语法:

template
class classname
{
  // body of class;
};

模板类对象的语法:

classname objectname(arglist);

38)函数重载和运算符重载有什么区别?

函数重载:定义函数重载是因为我们可以拥有同一函数的多个版本。函数的版本将具有不同的签名,这意味着它们具有不同的参数集。

运算符重载:定义运算符重载是因为可以重新定义标准运算符,以便在应用于类的实例时具有不同的含义。

39)什么是虚拟析构函数?

基类使用C++中的虚拟析构函数,以便也可以销毁派生的类对象。通过使用〜波浪号运算符,然后在构造函数之前使用virtual关键字,可以声明虚拟析构函数。

注意:构造函数不能是虚拟的,但是析构函数可以是虚拟的。

让我们通过一个例子来理解

  • 不使用虚拟析构函数的示例
#include 
using namespace std;
class Base
{
    public:
    Base()
    {
        cout<<"Base constructor is called"<<"\n";
    }
    ~Base()
    {
        cout<<"Base class object is destroyed"<<"\n";
    }
};
class Derived:public Base
{
    public:
    Derived()
    {
        cout<<"Derived class constructor is called"<<"\n";
    }
    ~Derived()
    {
        cout<<"Derived class object is destroyed"<<"\n";
    }
};
int main() 
{
  Base* b= new Derived;
  delete b;
  return 0;
  
}

输出:

Base constructor is called
Derived class constructor is called
Base class object is destroyed

在上面的示例中,delete b将仅调用基类析构函数,这是因为派生类析构函数保持不变。这导致内存泄漏。

  • 虚拟析构函数示例
#include 
using namespace std;
class Base
{
    public:
    Base()
    {
        cout<<"Base constructor is called"<<"\n";
    }
    virtual ~Base()
    {
        cout<<"Base class object is destroyed"<<"\n";
    }
};
class Derived:public Base
{
    public:
    Derived()
    {
        cout<<"Derived class constructor is called"<<"\n";
    }
    ~Derived()
    {
        cout<<"Derived class object is destroyed"<<"\n";
    }
};
int main() 
{
  Base* b= new Derived;
  delete b;
  return 0;
  
}

输出:

Base constructor is called
Derived class constructor is called
Derived class object is destroyed
Base class object is destroyed

当我们使用虚拟析构函数时,则首先调用派生类析构函数,然后再调用基类析构函数。