关于c++:C面试八股文C中设计一个类要注意哪些东西

3次阅读

共计 3104 个字符,预计需要花费 8 分钟才能阅读完成。

某日二师兄加入 XXX 科技公司的 C ++ 工程师开发岗位第 9 面:

面试官:C++ 中,设计一个类要留神哪些货色?

二师兄:设计一个类次要思考以下几个方面:1. 面向对象的封装、继承及多态。2.big three或者big five。3. 运算符和函数重载、动态成员、友元、异样解决等相干问题。

面试官:请介绍一下面向对象的三个个性。

二师兄:封装是将类的函数和数据封装起来,内部不能间接拜访类的数据,而是须要通过办法拜访数据。继承是指一个类能够继承另一个类的属性和办法。多态是指一个对象能够体现出多种状态。

面试官:请问多态是如何实现的?

二师兄:多态的是通过父类的指针或援用指向子类的对象实现的。在对象中保护一个虚指针(vtptr),这个指针指向一个虚表(vtable),当用户通过父类对象拜访子类的办法时,通过查问虚表中对应的办法的地址,并跳转到此地址执行间接拜访对象的办法。所以多态是有一点点运行时开销的。

面试官:你方才所说的 big threebig five是什么?

二师兄:(嘿嘿,被装到了)类的 big three 别离是拷贝构造函数(copy constructor)、拷贝赋值运算符(copy assignment)和析构函数。而类的 big five 则多了两个,别离是挪动构造函数(move constructor)和挪动赋值运算符(move assignment)。前面两个是 C ++11 之后引入的。

面试官:好的。那你晓得为什么要引入挪动结构和挪动赋值吗?

二师兄:次要是为了效率。挪动结构和挪动赋值不须要把所有的数据从新拷贝一遍,而是霸占了被挪动对象的数据的所有权。代价是被挪动对象在被挪动后不能应用。

面试官:嗯。那你晓得为什么挪动结构和挪动赋值都要加上 noexcept 关键字吗?

二师兄:额。。。如同不让抛异样?

面试官:你晓得类的动态成员变量须要留神哪些问题吗?

二师兄:要留神哪些问题?额。。。

面试官:在成员办法后加 const 是为什么?

二师兄:次要是为了束缚这个成员办法不更改对象的任何数据。

面试官:还有其余的起因吗?

二师兄:如同没有了吧。。。

面试官:类的成员办法能够通过 const 符号重载吗?

二师兄:这个,,应该能够吧。。

面试官:你晓得什么是类的成员办法的援用限定符吗?

二师兄:没有据说过耶。。。

面试官:好的,回去等告诉吧。

让咱们来看一看今日二师兄的体现吧,

为什么挪动结构和挪动赋值都要加上 noexcept 关键字?

因为在应用挪动语义时,通常会将资源的所有权从一个对象转移到另一个对象,而不是复制资源。如果抛出异样,那么在转移资源的过程中可能会呈现问题,导致资源透露或其余不可预测的行为。

另外,加上 noexcept 关键字还能够进步代码的性能,因为编译器能够在不必要的状况下进行优化。

类的动态成员变量须要留神哪些问题?

动态成员变量的初始化程序是不确定的。如果一个动态成员变量依赖于另一个动态成员变量的值,要确保第二个动态化成员先被初始化,否则程序可能会呈现未定义的行为。

动态成员变量的值能够被多个实例同时批改,因而在多线程拜访动态成员时要留神数据竞争问题。动态变量的生命周期与程序的生命周期雷同,因而它们可能会占用大量的内存。

在成员办法后加 const 是为什么?

一是能够束缚此办法不会更改对象的任何数据。二是 cosnt 对象也能够拜访此成员办法。

#include <iostream>
struct Foo
{void f1(){std::cout <<"f1" << std::endl;}
    void f2() const{std::cout <<"f2" << std::endl;}
};
int main(int argc, char const *argv[])
{
    Foo foo;
    foo.f1();
    foo.f2();
    const Foo& foo2 = foo;
    foo2.f1();  // 这里无奈通过编译,因为 const 对象无法访问非 const 办法
    foo2.f2();  // 这里能够通过编译}

类的成员办法能够通过 const 符号重载吗?

这是一个很好的问题,预计很多人没有思考过。先说答案,底层 const 能够,而顶层 const 不能够。

#include <iostream>
struct Foo{};
struct Goo
{void f1(Foo& f){std::cout <<"non const function" << std::endl;}
    void f1(const Foo& f){std::cout <<"const function" << std::endl;}
};
int main(int argc, char const *argv[])
{
    Foo foo;
    Goo goo;
    goo.f1(foo);    // 无奈通过编译,error:‘void Goo::f1(Foo)’cannot be overloaded with‘void Goo::f1(Foo)’return 0;
}

当咱们把顶层 const 改为底层const

#include <iostream>
struct Foo{};
struct Goo
{void f1(Foo& f){std::cout <<"non const function" << std::endl;}
    void f1(const Foo& f){std::cout <<"const function" << std::endl;}
};
int main(int argc, char const *argv[])
{
    Foo non_const_foo;
    const Foo const_foo;
    Goo goo;
    goo.f1(non_const_foo);    // 能够通过编译    non const function
    goo.f1(const_foo);    // 能够通过编译 const function
    return 0;
}

那么咱们是否通过在函数括号后加上 const 来重载函数呢?

#include <iostream>
struct Goo
{void f1() {std::cout <<"non const function" << std::endl;}
    void f1() const{std::cout <<"const function" << std::endl;}
};
int main(int argc, char const *argv[])
{
    Goo non_const_goo;
    const Goo const_goo;
    non_const_goo.f1();   
    const_goo.f1();   
    return 0;
}

答案是必定的,因为const_goo.f1() 能够等同于f1(const Goo* goo),也是底层const

最初一个问题尽管简略,但我置信至多有 80% 的 C ++ 程序员不晓得是什么,

什么是类的成员办法的援用限定符吗?

类的成员办法的援用限定符是 C++11 中引入的一种新个性,用于指定成员办法的参数是左值援用还是右值援用。

#include <iostream>
struct Foo
{void f1() & {std::cout << "only left reference can call this function" << std::endl;}
    void f1() && {std::cout << "only right reference can call this function" << std::endl;}
};
int main(int argc, char const *argv[])
{
    Foo foo;
    foo.f1();       //left reference
    Foo().f1();     //right reference
    return 0;
}

好了,今日份面试到这里就完结了,小伙伴们,对于明天二师兄的面试,能打几分呢?如果是你,以上的问题都能答复的上来吗?

关注我,带你 21 天“精通”C++!(狗头)

正文完
 0