C++校招八股

news2024/11/20 2:21:48

c++类的访问权限与继承方式

  1. 公有成员在任何地方都可以被访问,包括类的外部和派生类。
  2. 受保护成员在类的内部和派生类中可以被访问,但在类的外部不可访问。
  3. 私有成员只能在类的内部访问,包括类的成员函数和友元函数,不允许在类的外部或派生类中访问。

#include <iostream>
#include <string>
using namespace std;
class Parent
{
    // 公有成员在任何地方都可以被访问,包括类的外部和派生类。
public:
    string name;
    void info_init(string name,string car,int password){
        this->name=name;
        this->car=car;
        this->password=password;
    }
    void print_info(){
        cout<<"name:"<<name<<endl;
        cout<<"car:"<<car<<endl;
        cout<<"password:"<<password<<endl;
    }
    // 受保护成员在类的内部和派生类中可以被访问,但在类的外部不可访问。
protected:
    string car;
    // 私有成员只能在类的内部访问,包括类的成员函数和友元函数,不允许在类的外部或派生类中访问。
private:
    int password;
};

int main()
{
    Parent p1;
    p1.info_init("jay","NIO",10086);
    p1.print_info();
    return 0;
}

多态的构成条件

1.必须通过基类的指针或者引用调用虚函数

2.被调用的函数必须是虚函数,且派生类必须对基类的虚函数进行重写。重写的三同(函数名,参数,返回值)

3.派生类可不加virtual

#include <iostream>
#include <string>
using namespace std;
class Parent
{
public:
    virtual void buy_ticket()
    {
        cout << "成人--全价票" << endl;
    }
};

class Child : public Parent
{
public:
    void buy_ticket()
    {
        cout << "儿童--半价票" << endl;
    }
};

void func(Parent &p)
{
    p.buy_ticket();
}
int main()
{
    Parent p;
    Child c;
    func(p);
    func(c);
    return 0;
}

virtual修饰析构函数

虚析构函数可以确保首先调用子类的析构函数, 然后调用父类的析构函数 ;这样可以避免在释放子类对象时出现资源泄漏的情况 ;
当使用父类指针指向一个子类对象时,如果要通过 delete 释放该指针指向的对象,如果是正常的析构函数, 没有使用 virtual 定义虚析构函数 , 则只会调用父类的析构函数, 子类的析构函数不会被调用到 ;

#include <iostream>
#include <string>
using namespace std;
class Parent
{
public:
    Parent()
    {
        cout << "Parent()" << endl;
    }
    virtual ~Parent()
    {
        cout << "~Parent()" << endl;
    }
};

class Child : public Parent
{
public:
    Child()
    {
        cout << "Child()" << endl;
    }
    ~Child()
    {
        cout << "~Child()" << endl;
    }
};

void func(Parent *p)
{
    delete p;
}
int main()
{
    // Parent* p1 = new Parent();
    Child *p2 = new Child();
    func(p2);
    return 0;
}

c++11的override 和 final

  • fianl:修饰虚函数,表示该虚函数不能再被重写
  • 放在类的后面表示该类无法被继承,也就是阻止了从类的继承,放在虚函数后面该虚函数无法被重写,表示阻止虚函数的重载

  • override:检查派生类虚函数是否重写了基类某个虚函数,如果没有重写编译报错。

初始化列表 

 初始化列表是一种在构造函数初始化类成员变量的语法。初始化列表在构造函数体执行之前完成成员的初始化。这种方式有时候比在构造函数中使用赋值更高效,并且适用于那些成员变量是常量或者是引用的情况。

初始化列表用法

const成员变量、引用成员变量、没有默认构造函数的自定义类型成员只能在初始化列表初始化

#include <iostream>
#include <string>
using namespace std;
class Parent
{
public:
    string name;
    // 使用初始化列表可以确保所有成员变量在构造函数体执行前都已初始化
    //初始化列表能只能初始化一次,多次初始化会报错:
    Parent(string name =NULL, int wealth = -1, int password = -1) : name(name), wealth(wealth), password(password)
    {
        cout << "Name: " << name << '\t' << "wealth: " << wealth << '\t' << "password: " << password << endl;
    }

protected:
    int wealth;

private:
    int password;
};

int main()
{
    Parent p("jay", 10000, 10086);
    Parent p1("jj");
    return 0;
}

友元三种实现方式

友元(friend)是一种机制,允许一个类或者函数访问另一个类的私有成员。通过将其他类或函数声明为友元,可以使它们在访问另一个类的私有成员时绕过访问限制。

  1. 全局函数做友元
  2. 类做友元
  3. 成员函数做友元
#include <iostream>
#include <string>
using namespace std;
class Parent
{
    friend void globalFunc(Parent *p);//告诉编译器此函数为友元,可以访问类内私有成员

public:
    string name="jay";

protected:
    int wealth = 8848;

private:
    int password = 10086;
};
//全局函数做友元
void globalFunc(Parent *p)
{
    cout << p->name << endl;
    cout << p->wealth << endl;
    cout << p->password << endl;
}
int main()
{
    Parent p;
    globalFunc(&p);
    return 0;
}
#include <iostream>
#include <string>
using namespace std;
class Parent
{
    friend class GrandParent;//告诉编译器此函数为友元,可以访问类内私有成员

public:
    string name="jay";

protected:
    int wealth = 8848;

private:
    int password = 10086;
};
class GrandParent{
public:
    void getInfo(Parent *p);
};
//全局函数做友元
void GrandParent::getInfo(Parent *p)
{
    cout << p->name << endl;
    cout << p->wealth << endl;
    cout << p->password << endl;
}
int main()
{
    Parent p;
    GrandParent g;
    g.getInfo(&p);
    return 0;
}
#include <iostream>
#include <string>
using namespace std;
class GrandParent
{
public:
    void getInfo();
    void getInfo1();
};

class Parent
{

    friend void GrandParent::getInfo(); // 告诉编译器此函数为友元,可以访问类内私有成员

public:
    string name = "jay";

protected:
    int wealth = 8848;

private:
    int password = 10086;
};

void GrandParent::getInfo()
{
    Parent*p=new Parent;
    cout << "getInfo(): " << p->name << "  " << p->wealth << "  " << p->password << endl;
}
void GrandParent::getInfo1()
{
    Parent*p=new Parent;

    // 无法访问
    //cout << "getInfo1(): " << p->name << "  " << p->wealth << "  " << p->password << endl;
}
int main()
{
    GrandParent g;
    g.getInfo();
    return 0;
}

C++几种构造函数

  1. 默认构造
  2. 有参构造
  3. 拷贝构造
  4. 移动构造函数:接受同一类的对象的右值引用作为参数,用于将资源从一个对象转移到另一个对象,通常用于提高效率。
#include <iostream>
#include <string>
using namespace std;
class MyClass
{
public:
    string data;
    // 默认构造函数:无参数的构造函数,如果类没有定义任何构造函数,则编译器会自动生成默认构造函数。
    // 默认构造函数被用于创建对象时,如果没有提供参数,会被调用。
    MyClass()
    {
        this->data = "默认构造函数";
        cout << "默认构造函数" << endl;
    }
    // 参数化构造函数:带有参数的构造函数,用于接受特定参数来初始化对象的成员变量。
    MyClass(string str) : data(str)
    {
        cout << "有参数构造函数" << endl;
    }
    // 拷贝构造函数:接受同一类的对象作为参数,用于以同一类对象的内容创建新对象。通常用于对象的深拷贝。
    MyClass(const MyClass &obj) : data(obj.data)
    {
        cout << "拷贝构造函数" << endl;
    }
    ~MyClass(){
        cout<<"-----------------------"<<endl;
    }
};

int main()
{
    MyClass obj;
    MyClass obj1("hello");
    MyClass obj2(obj1);
    return 0;
}

 指针和引用

  • 指针是一个变量,其值为另一个变量的地址;引用是一个别名,它相当于已经存在变量的另一个名字。
  • 使用指针可以直接访问或修改内存中的数据。
  • 指针可以被重新赋值指向不同的地址,甚至可以指向空值(nullptr);引用必须在定义时初始化,并且一旦初始化后不能再引用其他变量
  • 指针需要解引用操作符 * ;引用可以直接访问原始变量的值,而不需要解引用操作符
  • 指针本身占用内存空间;而引用不占用额外的内存空
#include <iostream>
#include <string>
using namespace std;

int main()
{
    int x = 10;
    int *p = &x;  // 指针是一个变量,其值为另一个变量的地址
    int &ref = x; // 引用是一个别名,它相当于已经存在变量的另一个名字;引用必须在定义时初始化,并且一旦初始化后不能再引用其他变量
    cout << "x=" << x << " *p=" << *p << " ref=" << ref << " p=" << p << endl;
    x = 20;
    cout << "x=" << x << " *p=" << *p << " ref=" << ref << " p=" << p << endl;
    *p = 30;
    cout << "x=" << x << " *p=" << *p << " ref=" << ref << " p=" << p << endl;
    ref = 40;
    cout << "x=" << x << " *p=" << *p << " ref=" << ref << " p=" << p << endl;

    return 0;
}

new/delete与malloc/free的异同

相同点

  1. 都可用于内存的动态申请和释放

不同点

  1. 前者是C++运算符,后者是C/C++语言标准库函数
  2. new自动计算要分配的空间大小,malloc需要手工计算
  3. new是类型安全的,返回完整的类型;malloc不是。
  4. new调用名为operator new的标准库函数分配足够空间并调用相关对象的构造函数,delete对指针所指对象运行适当的析构函数;然后通过调用名为operator delete的标准库函数释放该对象所用内存。后者均没有相关调用
  5. 后者需要库文件支持,前者不用;new是封装了malloc,直接free不会报错,但是这只是释放内存,而不会析构对象

解释每个示例的含义

//声明了一个数组 p,数组中包含 10 个指向 int 类型的指针
int *p[10];
//一个指针 p,它指向一个包含 10 个 int 类型元素的数组。
int (*p)[10];
//声明了一个函数 p,该函数接受一个 int 类型的参数,并返回一个 int 类型的指针。
int *p(int);
//声明了一个指针 p,它指向一个函数,该函数接受一个 int 类型的参数,并返回一个 int 类型的值
int (*p)(int);

static在类中的作用

静态成员变量 

  1. static + 类型+变量名后,那么该类 不论 创建了多少个 实例对象 , 这些对象都会共享 该 static " 静态成员变量 " ;
  2. 成员变量一旦加了static关键字后就会处在静态区的,类是处在栈区的, 所以静态的成员变量只能在类外去定义,类内只能是声明,而且不可赋值!!!
  3. 静态成员变量 的 生命周期 就是 程序的声明周期 ;静态成员变量在 应用启动时 初始化 , 在 进程结束时销毁 ;

静态成员变函数 

  1. 静态成员函数没有隐藏的this指针,不能访问任何非静态成员
  2. 静态成员也是类的成员,受public、protected、private 访问限定符的限制
#include <iostream>
#include <string>
using namespace std;
class Person
{
public:
    Person()
    {
        this->var++;
        this->s_var++;
        cout << "Person(): var=" << this->var <<" s_var="<<this->s_var<<" constVar=" <<this->constVar<<endl;
    }
    ~Person()
    {
        this->var--;
        this->s_var--;
        cout << "~Person(): var=" << this->var <<" s_var="<<this->s_var<<" constVar=" <<this->constVar<<endl;
    }
    static int s_var; // 必须在类内定义,类外初始化,static int s_var=0会报错
    int var=0;//非静态变量可以类内声明并定义.但是不可外部定义
    const int constVar=0;
    static void staticFinc()
    {
        cout << s_var << endl;//静态成员函数没有隐藏的this指针,不能访问任何非静态成员
        //cout << var << endl;
    }
    
};
int Person::s_var = 0; // 在类外部初始化静态成员变量
//int Person::var = 0; // 不可在类外部初始化非静态成员变量
//int Person::constVar=100;
int main()
{
    Person p;
    Person p1;
    return 0;
}

C++ class与struct区别

相同点

  1. 两者都拥有成员函数、公有和私有部分
  2. 任何可以使用class完成的工作,同样可以使用struct完成

不同点

  1. 两者中如果不对成员不指定公私有,struct默认是公有的,class则默认是私有的
  2. class默认是private继承,而struct默认是public继承
#include <iostream>
#include <string>
using namespace std;
struct Person
{
    Person()
    {
        this->name="NULL";
        this->age=-1;
        this->password=-1;
        cout << "Person()" << endl;
    }
    ~Person(){
        cout << "~Person()" << endl;

    }
    void print_info(){
        cout<<"name:"<<name<<" age:"<<age<<" password:"<<password<<endl;
    }
    string name;

protected:
    int age;

private:
    int password;
};
struct Student:Person {
    Student()
    {
        cout << "Student()" << endl;
    }
    ~Student(){
        cout << "~Student()" << endl;

    }

};
int main()
{
    Person p;
    Student s;
    p.name="person";//struct默认是public继承,因此可以访问公有成员
    s.name="student";
    p.print_info();
    s.print_info();
    return 0;
}

C++的顶层const和底层const

概念区分

  • 顶层const:指的是const修饰的变量本身是一个常量,无法修改,指的是指针,就是*号的右边
  • 底层const:指的是const修饰的变量所指向的对象是一个常量,指的是所指变量,就是*号的左边 
int a = 10;int* const b1 = &a;        //顶层const,b1本身是一个常量
const int* b2 = &a;       //底层const,b2本身可变,所指的对象是常量
const int b3 = 20; 		   //顶层const,b3是常量不可变
const int* const b4 = &a;  //前一个const为底层,后一个为顶层,b4不可变
const int& b5 = a;		   //用于声明引用变量,都是底层const

拷贝初始化和直接初始化

在 C++ 中,初始化对象的方式可以分为两种:拷贝初始化(copy initialization)和直接初始化(direct initialization)。

1. 拷贝初始化(Copy Initialization):

  •    使用等号=进行初始化的方式称为拷贝初始化。
  • 在拷贝初始化中,编译器会尝试使用构造函数将右侧的值转换为左侧的类型,并将结果拷贝到左侧的对象中。这种初始化方式适用于将一个对象的值拷贝给另一个对象,或者通过一个值来初始化一个新的对象。

2. 直接初始化(Direct Initialization):

  • 在初始化过程中直接使用圆括号()进行初始化的方式称为直接初始化。
  • 在直接初始化中,编译器会选择合适的构造函数来初始化对象,而不需要进行额外的拷贝操作。

静态类型,动态类型;静态绑定,动态绑定

对C++中的静态类型,动态类型,静态绑定,动态绑定的理解_静态类型和动态类型,静态绑定和动态绑定-CSDN博客

  1. 静态类型变量声明时候的类型,在编译阶段就可以确定了
  2. 动态类型指针或者引用所代表的内存中的对象的类型,在运行阶段才可以确定
  3. 静态绑定:有人也叫为早绑定,早绑定什么呢?对象所调用的函数的地址,这个阶段是程序编译阶段就确定的了;
  4. 动态绑定:有人也叫晚绑定,也就是编译阶段时候不能确定对象调用函数的地址,需要程序运行到调用函数的阶段才可以确定;

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1642005.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

应用分层和企业规范

目录 一、应用分层 1、介绍 &#xff08;1&#xff09;为什么需要应用分层&#xff1f; &#xff08;2&#xff09;如何分层&#xff1f;&#xff08;三层架构&#xff09; MVC 和 三层架构的区别和联系 高内聚&#xff1a; 低耦合&#xff1a; 2、代码重构 controlle…

【软件测试】测试用例设计方法

1. 等价类划分法1.1. 等价类划分法的定义1.2. 有效等价类和无效等价类1.3. 等价类划分法实例分析 2. 边界值分析法2.1. 边界值分析法的定义2.2. 边界点2.3. 边界值法实例分析 3. 判定表法3.1. 如何用判定表法设计测试用例3.2. 判定表法实例分析 4. 正交表法4.1. 什么是正交表4.…

模拟实现memcpy,memmove,memset,memcmp

memcpy void * memcpy ( void * destination, const void * source, size_t num ); 使用注意事项&#xff1a; 从source的位置向后复制num个字节数据到destination所指向的内存位置中。 这个函数遇到如果源空间和⽬标空间出现重叠&#xff0c;就得使⽤memmove函数处理。 …

纯血鸿蒙APP实战开发——自定义路由栈管理

介绍 本案例将介绍如何使用路由跳转返回时获取到来源页的模块名以及路径名&#xff0c;在实际场景中同一页面通常会根据不同来源页展示不同的UI。 使用说明 无特殊使用说明&#xff0c;其他使用说明参考动态路由的相关说明 实现思路 路由来源页的实现 新增来源页字段 ex…

【刷题篇】动态规划-二维费用的背包问题(十二)

文章目录 1、一和零2、盈利计划3、组合总和 Ⅳ4、不同的二叉搜索树(卡特兰数) 1、一和零 给你一个二进制字符串数组 strs 和两个整数 m 和 n 。 请你找出并返回 strs 的最大子集的长度&#xff0c;该子集中 最多 有 m 个 0 和 n 个 1 。 如果 x 的所有元素也是 y 的元素&#x…

vue快速入门(五十三)使用js进行路由跳转

注释很详细&#xff0c;直接上代码 上一篇 新增内容 几种常用的路由跳转方式演示 源码 App.vue <template><div id"app"><div class"nav"><!-- router-link 自带两个高亮样式类 router-link-exact-active和router-link-active区别&a…

AI代理架构的发展:从单一到多代理系统的演进及其影响分析

每周跟踪AI热点新闻动向和震撼发展 想要探索生成式人工智能的前沿进展吗&#xff1f;订阅我们的简报&#xff0c;深入解析最新的技术突破、实际应用案例和未来的趋势。与全球数同行一同&#xff0c;从行业内部的深度分析和实用指南中受益。不要错过这个机会&#xff0c;成为AI领…

数字逻辑之“逻辑门电路”

一、基础知识 1、正逻辑和负逻辑 &#xff08;1&#xff09;基本的逻辑规定 1——“真”0——“假” &#xff08;2&#xff09;正逻辑和负逻辑 在实际的数字系统中&#xff0c;用数字信号&#xff08;逻辑电平U1&#xff0c;U2&#xff09;表示“真&#xff08;1&#xf…

FloodFill-----洪水灌溉算法(DFS例题详解)

目录 一.图像渲染&#xff1a; 代码详解&#xff1a; 二.岛屿数量&#xff1a; 代码详解&#xff1a; 三.岛屿的最大面积&#xff1a; 代码详解&#xff1a; 四.被围绕的区域&#xff1a; 代码详解&#xff1a; 五.太平洋大西洋水流问题&#xff1a; 代码详解&#x…

[leetcode] B树是不是A树的子结构

给定两棵二叉树 tree1 和 tree2&#xff0c;判断 tree2 是否以 tree1 的某个节点为根的子树具有 相同的结构和节点值 。 注意&#xff0c;空树 不会是以 tree1 的某个节点为根的子树具有 相同的结构和节点值 。 示例 1&#xff1a; 输入&#xff1a;tree1 [1,7,5], tree2 [6,…

Docker-compose部署LTC同步节点

1、下载ltc程序包&#xff0c;litecoin下载地址 下载页 mkdir /data/docker-compose/ltc cd /data/docker-compose/ltc https://github.com/litecoin-project/litecoin/releases/download/v0.21.3/litecoin-0.21.3-x86_64-linux-gnu.tar.gz2、编写dockerfile和bitcoin.conf b…

M2M vs. IoT?

有任何关于GSMA\IOT\eSIM\RSP\业务应用场景相关的问题&#xff0c;欢迎W: xiangcunge59 一起讨论, 共同进步 (加的时候请注明: 来自CSDN-iot). 连接设备已经开辟了创造价值和解决重大世界问题的广泛机会&#xff0c;例如可持续发展。 今天&#xff0c;我们网络设备的方式可…

tomcat打开乱码修改端口

将UTF-8改成GBK 如果端口冲突&#xff0c;需要修改tomcat的端口

智慧校园云平台源码,SaaS运营云平台(支持多学校、多校园使用)

智慧班牌系统&#xff0c;又称电子班牌系统&#xff0c;是一种基于互联网技术的综合管理工具。通过在教室内安装显示屏&#xff0c;并连接到学校管理系统&#xff0c;实现教学资源展示、信息发布、学生管理等多种功能的集成。该系统旨在加强学校班级文化建设和班级风采展示&…

Gitea 上传用户签名

在 Gitea 的用户管理部分&#xff0c;有一个 SSH 和 GPG 的选项。 单击这个选项&#xff0c;可以在选项上添加 Key。 Key 的来源 如是 Windows 的用户&#xff0c;可以选择 Kleopatra 这个软件。 通过这个软件生成的 Key 的界面中有一个导出功能。 单击这个导出&#xff0c;…

84、动态规划-完全平方数

思路 第一种递归方式&#xff1a; public static int numSquares3(int n) {if (n<2){return n;}return process(n);}private static int process(int rest) {if (rest<0){return 0;}int minrest;for (int i 2; i*i <rest ; i) {int countrest/(i*i);for (int j 1;…

初始Java篇(JavaSE基础语法)(6)(继承和多态)(下)

找往期文章包括但不限于本期文章中不懂的知识点&#xff1a; 个人主页&#xff1a;我要学编程(ಥ_ಥ)-CSDN博客 所属专栏&#xff1a;JavaSE 多态篇 目录 多态的概念 实现多态的条件 必须在继承体系下实现向上转型&#xff1a; 子类必须对父类中的方法进行重写&#xff1…

Wireshark CLI | 过滤包含特定字符串的流

问题背景 源自于和朋友的一次技术讨论&#xff0c;关于 Wireshark 如何查找特定字符串所在的 TCP 流&#xff0c;原始问题如下&#xff1a; 仔细琢磨了下&#xff0c;基于我对 Wireshark 的使用经验&#xff0c;感觉一步到位实现比较困难&#xff0c;所以想着说用 Wireshark C…

Tomcat启动闪退怎么解决(文末附终极解决方案)

AI是这么告诉我的 Tomcat启动时出现闪退问题可能由多种原因引起&#xff0c;以下是解决此类问题的一些通用方法&#xff1a; 检查环境变量&#xff1a; 确保已经正确设置了JAVA_HOME和JRE_HOME环境变量&#xff0c;并指向正确的Java安装路径。将Java的bin目录添加到系统的PATH…

用户中心(下)

文章目录 计划登录逻辑接口简单说明cookie和session写代码流程后端逻辑层控制层测试用户管理接口 前端简化代码对接后端代理 计划 开发完成后端登录功能 &#xff08;单机登录 > 后续改造为分布式 / 第三方登录&#xff09;✔开发后端用户的管理接口 &#xff08;用户的查询…