C++基础知识(1)

1、static关键字的作用

static关键字主要是使变量或者函数成为静态的,并存储在静态存储区

static用途有以下五种: 全局静态变量、局部静态变量、静态函数、类的静态数据成员、类的静态函数

(1)在全局变量前面加上关键字static,全局变量就成为静态全局变量,在整个程序运行期间一直存在,全局静态变量在声明它的文件之外是不可见的

(2)同理在局部变量之前加上static,局部变量就变成了局部静态变量,局部静态变量作用域仍在局部作用域,当定义它的函数或者语句块结束时,作用域结束。但是局部静态变量并没有被销毁,而是仍然驻留在内存中,只不过我们不能再对它进行访问,直到该函数再次被调用才能访问并且其值不变。

(3)在函数返回类型前面加上static,函数就定义为静态函数。函数的定义和声明在默认情况下都是extern的,但静态函数只是在声明他的文件中可见,不能被其他文件所用。一般情况下,如果需要在多个cpp中复用该函数,那么就把该函数的声明提到头文件中,否则在cpp内部声明该函数并加上static修饰。

(4)在类中,静态成员是类的所有对象中共享的成员,而不是某个对象成员,对多个对象来说,静态数据成员只存储一处,供所有对象共用。

(5)静态成员函数跟静态数据成员一样都是类的静态成员,因此对静态成员的引用不需要实例化一个对象来调用,直接用类名加双冒号既可以调用。

2、C++和C的区别

(1)设计思想上

C++是面向对象的语言,而C是面向过程的结构化编程语言

(2)语法上

C++具有重载、继承和多态三种特性

C++相比C,增加许多类型安全的功能,例如强制类型转换

C++支持范式编程,比如模板类、函数模板等

C++有引用,而C没有

3、什么是面向对象与面向过程,两者有何区别与优缺点?

(1)什么是面向对象与面向过程

面向过程就是分析出问题所需要的步骤,然后用函数把这些步骤一步一步实现,使用的时候一个一个依次调用就可以;而面向对象是把构成问题的事务分解成各个对象,建立对象的目的不是为了完成一个步骤,而是为了描述某个事物在整个解决问题的步骤中的行为。

(2)两者区别

面向过程简单直接,容易入门,模块化程度低;而面向对象需要抽离出问题事务的对象,较为复杂,但模块化程度高,代码复用高,扩展性强;虽然面向对象前期开发要把面向过程复杂,但是后期维护和扩展要远比面向过程简单。

(3)举例说明

五子棋系统: 面向过程设计思路:

步骤1:开始游戏

步骤2:黑子先走

步骤3:绘制画面

步骤4:判断输赢

步骤5:轮到白子

步骤6:绘制画面

步骤7:判断输赢

步骤8:返回步骤2

步骤9:输出最后结果

面向对象的设计思路:

整个五子棋可以分为: (a)玩家对象,即黑白双方,这两方的行为是一致的

(b) 棋盘系统,负责绘制画面 (c) 规则系统,负责判定诸如犯规、输赢等

第一类对象(玩家对象)负责接受用户输入,并告知第二类对象(棋盘系统)棋子布局的变化,棋盘对象接收到棋子的变化就要负责在屏幕显示出这种变化,同时利用第三类对象(规则系统)来对棋局进行判定。

4、说一下C++中四种cast转换

C++的四种类型转换是:static_cast、dynamic_cast、const_cast、reinterpret_cast____

(1)const_cast

用于将const变量转化为非const

(2)static_cast

用于各种隐式转换,比如非const转const,void*转指针等,static_cast能用于多态向上转化,如果向下转能成功但是不安全,结果未知。

(3)dynamic_cast

用于动态类型转化,只能用于含有虚函数的类,用于类层次间的向上和向下转化。只能转指针或引用。向下转化时,如果是非法的,对于指针返回NULL,对于引用抛出异常。(向上转换:指的是子类向基类的转换;向下转换:指的是基类向子类转换)

(4)reinterpret_cast

几乎什么都可以转,比如将int转换为指针,可能会出问题,尽量少用。

(5)为什么不使用C的强制转换

C的强制转换表面上看起来功能强大,但是转化不够明确,不能进行错误检查,容易出错。

5、请说一下C/C++中指针和引用的区别

(1)指针有自己的一块空间,而引用只是一个别名

(2)使用sizeof看一个指针大小是4,而引用则是被引用对象的大小

(3)指针可以被初始化为NULL,而引用必须被初始化且必须是一个已有的对象的引用

(4)作为参数传递时,指针需要被解引用才可以对对象进行操作,而直接对引用修改都会改变引用所指向的对象

(5)可以有const指针,但是没有const引用

(6)指针在使用中可以指向其他对象,但是引用只能是一个对象的引用,不能被改变

(7)指针可以有多级指针,而引用只有一级

(8)指针和引用使用++运算符意义不一样

(9)如果返回动态内存的对象或者内存,必须使用指针,引用可能会引起内存泄漏

6、请你说一下你理解的C++中的智能指针

C++里面有四个智能指针:auto_ptr,shared_ptr,weak_ptr,unique_ptr其中后三个是C++11支持的,并且第一个已经被C++11弃用了。

为什么要使用智能指针呢?

智能指针的作用是管理一个指针,因为存在以下这种情况:申请的空间在函数结束时忘记释放,造成内存泄漏。使用智能指针可以很大程度上避免这个问题,因为智能指针就是一个类,当超出了类的作用域,类会自动调用析构函数,析构函数会自动释放资源,所以指针指针的作用原理就是在函数结束时自动释放内存空间,不需要手动释放内存空间。

(1)auto_ptr(C++98的方案,C++11已经抛弃)

采用所有权的模式。

auto_ptr<string>p1(new string ("Hello World"));
auto_ptr<string>p2;
p2 = p1; // auto_ptr不会报错

此时不会报错,但是p2剥夺了p1的所有权,当程序运行时访问p1将会报错。所以auto_ptr的缺点是:存在潜在的内存崩溃问题。

(2)unique_ptr(替换auto_ptr)

unique_ptr实现独占式拥有或者严格拥有概念,保证同一时间内只能有一个智能指针可以指向该对象。它对于避免资源泄漏特别有用。

unique_ptr能够取代auto_ptr是因为unique_ptr更安全,当程序试图将一个unique_ptr赋值给另一个时,如果源unique_ptr是个临时右值,编译器运行这样做;否则编译器会报错。

eg:

 unique_ptr<string>pu1(new string("hello world"));
 unique_ptr<string>pu2;
 pu2 = pu1; // #1 报错
 unique_ptr<string>pu3;
 pu3 = unique_ptr<string>(new string("hello world")); // #2 允许

如果确定要想执行#1的操作,要安全地重用这种指针,可以给它赋新值。C++有一个标准库函数,std::move(),可以将一个unique_ptr赋值给另一个。

 unique_ptr<string>ps1(new string("hello world"));
 unique_ptr<string>ps2;
 ps2 = std::move(ps1);
 ps1 = nullptr;

(3)shared_ptr

shared_ptr顾名思义是具有共享的概念,多个智能指针可以指向同一个对象,该对象和其他相关资源在最后一个引用被销毁时释放。可以使用use_count()来查看该资源被多少个智能指针共享。

(4)weak_ptr

weak_ptr是对对象的一种弱引用,不控制对象生命周期的智能指针,其构造与析构不会引起引用参数的改变,它指向一个share_ptr管理的对象,而且仅提供对管理对象的访问手段。weak_ptr设计目的是为了解决share_ptr相互引用的死锁问题,如果两个shared_ptr相互引用,那么者两个指针的引用计数永远不可能下降为0,资源永远不会释放。

class B;
class A
{
public:
    shared_ptr<B>pb_;
    ~A() {cout<<"A delete"<<endl;}
};

class B
{
public:
    shared_ptr<A>pa_;
    ~B() {cout<<"B delete"<<endl;}
};

void fun()
{
    shared_ptr<B> pb(new B());
    shared_pte<A> pa(new A());
    pb->pa_ = pa;
    pa->pb_ = pb;
    cout<<pb.use_count()<<end;
    cout<<pa.use_count()<<endl;
}
int main(){
    fun();
    return 0;
}

由上面例子可以看出,fun函数中,pa和pb之间相互引用,两个资源引用计数为2,当要跳出函数时,pa和pb析构引用计数减1,但是两者引用计数还是为1,导致跳出函数时还没有释放资源(A,B的析构没有被调用),如果把其中一个改成weak_ptr就可以了。假如把类A中的shared_ptr pb_改为weak_ptr pb_,这样资源B的引用开始就只有1,当pb析构时,B的计数变为0,B释放,B释放同时也会使A的计数减1,同时pa析构时使A计数减1,那么A的计数为0,A得到释放。_

我们不能通过weak_ptr直接访问对象的方法,比如B中对象有一个方法为print(),不能pa->pb_->print();因为pb_是一个weak_ptr,应该先把它转化为shared_ptr,shared_ptr p = pa->pb_.lock(); p->print();

7、C++中NULL与nullptr的区别

(1)C语言中的NULL

首先在C语言中NULL通常被定义为:#define NULL((void*)0),在C语言中把空指针NULL赋值给其他特定类型的指针时会发生隐式类型转换,把void指针转换为相应类型的指针

eg:

int* p1 = NULL;
char* p2 = NULL;

(2) C++中的NULL与nullptr

C++是强类型语言,void*不能隐式转换成其他类型指针,所以以上代码用C++编译是错误的。事实上,编译器提供的头文件做了相应的处理

#ifdef __cplusplus 
#define NULL 0 
#else 
#define NULL ((void *)0) 
#endif

可见,在C++中,NULL实际上是0,如果依旧把NULL当作空指针,则容易引起问题,比如函数重载的时候,形参如果有int类型和void类型,那么实参传进NULL,则会选择int类型的版本。因此为了避免从C语言遗留下来的二义性问题,C++11新定义了一个关键字nullptr来代表空指针nullptr。如果上述重载函数传进的是nullptr,那么选择重载版本的形参是void类型

综上,在C++中NULL就是0,而nullptr在任何情况下都是代表空指针。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

czy1219

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值