首页 > 编程语言 >C++ 面试题

C++ 面试题

时间:2024-01-17 18:14:16浏览次数:19  
标签:面试题 函数 C++ 表是 函数指针 构造函数 指针

目录


构造函数不能声明为虚函数

在C++中,构造函数不能声明为虚函数。这是因为在执行类的构造函数时,内存中还没有虚表,也就是还没有定义虚指针。因此,构造函数必须始终是非虚的。这是C++语言设计的一部分,以确保在对象构造期间能够正确地初始化虚函数表和虚指针。因此,构造函数不能声明为虚函数。

但是,C++中可以有虚析构函数。以下是一个示例代码:

#include<iostream>
using namespace std;

class Base {
public:
    Base() {
        cout << "Constructing base \n";
    }
    virtual ~Base() {
        cout << "Destructing base \n";
    }
};

class Derived : public Base {
public:
    Derived() {
        cout << "Constructing derived \n";
    }
    ~Derived() {
        cout << "Destructing derived \n";
    }
};

int main(void) {
    Derived *derived = new Derived();
    Base *bptr = derived;
    delete bptr;
    return 0;
}

输出结果为:

Constructing base
Constructing derived
Destructing derived
Destructing base

这个例子展示了虚析构函数的用法。


虚函数表是如何在C++中被初始化的?

在C++中,虚函数表(vtable)是在对象的构造期间被初始化的。虚函数表是一个存储类的虚函数指针的数组,用于实现多态性。在对象构造期间,虚函数表会被填充为指向正确的虚函数的指针。

具体来说,虚函数表是在执行类的构造函数期间被初始化的。在构造函数执行期间,会为对象分配内存并初始化虚函数表。这确保了在对象构造期间能够正确地设置虚函数表和虚指针,以便在运行时进行正确的多态调用。

以下是一个示例代码,展示了虚函数表是如何在C++中被初始化的:

#include <iostream>
using namespace std;

class Base {
public:
    virtual void func() {
        cout << "Base::func()" << endl;
    }
};

class Derived : public Base {
public:
    void func() override {
        cout << "Derived::func()" << endl;
    }
};

int main() {
    Base* basePtr = new Derived();
    basePtr->func(); // 输出 "Derived::func()"
    delete basePtr;
    return 0;
}

在这个示例中,Base 类和 Derived 类都有一个虚函数 func。在 main 函数中,我们创建了一个 Derived 类的对象,并将其赋值给 Base 类的指针。当调用 basePtr->func() 时,会根据虚函数表中的指针调用 Derived::func(),实现了多态性。


虚函数表和虚函数指针在内存中的具体存储方式是什么?

  1. 虚函数表(vtable)和虚函数指针在内存中的具体存储方式是这样的:虚函数表是一个指针数组,存储了该类的虚函数的地址。
  2. 每个类有一个虚函数表,其中存储了该类的虚函数的地址。
  3. 而虚函数指针是一个指向虚函数表的指针,它存储了虚函数表的地址。
  4. 当调用一个虚函数时,实际上是通过虚函数指针找到对应的虚函数表,再从虚函数表中找到对应的虚函数地址进行调用。

这样的设计实现了多态性,使得在运行时能够正确地调用对象的实际类型的虚函数。

标签:面试题,函数,C++,表是,函数指针,构造函数,指针
From: https://www.cnblogs.com/yubo-guan/p/17970664

相关文章

  • C++中setw和setfill函数的结合应用
    一、头文件头文件为#include<iomanip>其中io代表输入输出,manip是manipulator(操纵器)的缩写iomanip的作用:主要是对cin,cout之类的一些操纵运算子,比如setfill,setw,setbase,setprecision等等。它是I/O流控制头文件,就像C里面的格式化输出一样。二、setw函数s......
  • KY20 完数与盈数C++
    练习使用向量vector容器。遍历每个数取余就好了。然后记录下来。#include<iostream>#include<vector>usingnamespacestd;intmain(){vector<int>B;vector<int>C;for(inti=2;i<=60;i++){vector<int>A;intm;......
  • C++ STL标准模板库
    目录简介容器(Containers)迭代器(Iterators)算法(Algorithms)函数对象(FunctionObjects)适配器(Adaptors)分配器(Allocators)std::min_element()简介C++中的STL(标准模板库)可以分为六个部分,分别是容器(Containers)、迭代器(Iterators)、算法(Algorithms)、函数对象(FunctionObjects)、适配器(Adapto......
  • 前缀和求解(c++)
    数组ana1a2...an前缀和Si=a1+a2+...+ai①如何求②作用//一维数组前缀和的计算#include<iostream>usingnamespacestd;constintN=100010;inta[N],s[N];intn,m;intmain(){scanf("%d%d",&n,&m);for(inti=1;i<=n;......
  • C++11稳定性与兼容性机制
    字符串的原始字面量使用样例:R“xxx(rawstring)xxx”其中括号内的即是原始字面量,可以直接表示字符串而不需要做转义,需注意括号前后的xxx字符串会被忽略且必须一样stringstr="D:\hello\world\test.text";//1cout<<str<<endl;stringstr1="D:\\hello\\world\\tes......
  • 面试题:AtomicInteger底层是如何实现的?
    有过Java面试经验的同学,可能很多都被问过这样一个问题:说一说AtomicInteger底层是如何实现的。废话不多说,源码先贴出来:publicfinalintgetAndAddInt(Objectvar1,longvar2,intvar4){intvar5;do{var5=this.getIntVolatile(var1,var2);}whil......
  • c++语法
    基本语法C++是一种通用的编程语言,具有面向对象的特性。以下是一些C++的基本语法:注释:在C++中,注释可以使用//表示单行注释,或者使用/**/表示多行注释。cppCopycode/*这是多行注释*/头文件:C++中使用头文件来引入库和声明函数。#include<iostream>//输......
  • c++基础
    c++基础#include<iostream>usingnamespacestd;//定义类AAclassAA{private:inta;//私有数据成员apublic://构造函数,用于初始化aAA(intvalue){a=value;}//公有成员函数,用于获取a的值intGetValue(){retur......
  • C++:GDAL中CreateCopy()函数生成的栅格图像如何修改波段数?
      本文介绍基于C++语言GDAL库,为CreateCopy()函数创建的栅格图像添加更多波段的方法。  在C++语言的GDAL库中,我们可以基于CreateCopy()函数与Create()函数创建新的栅格图像文件。其中,CreateCopy()函数需要基于一个已有的栅格图像文件作为模板,将模板文件的各项属性信息(例如空......
  • C++学习日记 2024-1-16
    开始学习C++几天了,之前没有记录,从现在开始,记录一下学习过程复习与回忆:1.引用与指针共同优点:只用引用与指针,在传递参数时,可以减少拷贝,减少内存消耗,提高效率指针优点:指针比引用更强大,所有引用能做的事,指针都能做,指针缺点:危险,指针可以为空,指针指向地址,同一地址可以......