面试

     今天去了一家上市的公司面试C++岗位。笔试题感觉还好,初试的时候问了一下概念的东西,就被难住了,有的的确是没有用到过,有的是知道怎么用但是不知道怎么组织语言。虽然干了好多年了,但是由于半路出家,对于一些基础知识没有太注重,基本上是遇到那一块才会去了解这些。以后要系统的学一遍基础知识,常用的设计模式,网络编程也要注视起来。


     总结一下这次遇到的几个问题。

  1. 内存的分配情况
  2. 指针和引用的区别
  3. 浅拷贝和深拷贝
  4. 开多少线程最优
  5. 观察者模式


一、内存的分配情况:

C、C++内存分配方式有三种:

(1)从静态存储区域分配:

内存在程序编译时就已经分配好,这块内存在程序的整个运行期间都存在。速度快、不容易出错,因为有系统会善后。例如全局变量,static变量等。
(2)在栈上分配: 
在执行函数时,函数内局部变量的存储单元都在栈上创建,函数执行结束时这些存储单元自动被释放。栈内存分配运算内置于处理器的指令集中,效率很高,但是分配的内存容量有限。 
(3)从堆上分配: 
即动态内存分配。程序在运行的时候用 malloc 或 new 申请任意大小的内存,程序员自己负责在何时用free 或delete 释放内存。动态内存的生存期由程序员决定,使用非常灵活。如果在堆上分配了空间,就有责任回收它,否则运行的程序会出现内存泄漏,另外频繁地分配和释放不同大小的堆空间将会产生堆内碎块。

一个C、C++程序编译时内存分为 5大存储区:堆区、栈区、静态存储区(全局区)、文字常量区、程序代码区。

(1) 程序代码区
这个很简单,代码要执行,肯定要加载进内存, 我们不必关心。
 
(2) 文字常量区
一般我们这样定义一个字符串时,其是在文字常量区的:

char* s1 = "hello, world";
char* s2 = "hello, world";
if(s1 == s2)
    printf("s1和s2指向同一个在文字常量区的字符串");

这里, s1和s2指向的是同一个字符串
 
3. 静态存储区
全局变量,静态变量会放在这个区域,事实上,全局变量也是静态的。
 
以上1,2,3三个区域的内存在程序起来的时候就开辟好了的。
 
4. 栈
局部变量就是在栈里的。另外,函数调用时的参数也是在栈里的,这个现在不必关心
 
5. 堆
malloc或new出来的内存就是在堆里的,需要程序员自己管理清除。

二、指针和引用的区别

相同点:

    都是地址的概念;

    指针指向一块内存,它的内容是所指内存的地址;引用是某块内存的别名。

区别:

    1. 指针是一个实体,而引用仅是个别名;

    2. 引用使用时无需解引用(*),指针需要解引用;

    3. 引用只能在定义时被初始化一次,之后不可变;指针可变;

    4. 引用没有 const,指针有 const,const 的指针不可变; 定义引用的时候可以const啊

    5. 引用不能为空,指针可以为空;

    6. “sizeof 引用”得到的是所指向的变量(对象)的大小,而“sizeof 指针”得到的是指针本身(所指向的变量或对象的地址)的大小;

    typeid(T) == typeid(T&) 恒为真,sizeof(T) == sizeof(T&) 恒为真,但是当引用作为成员时,其占用空间与指针相同(没找到标准的规定)。

    7. 指针和引用的自增(++)运算意义不一样;

引用的一些规则如下:

    (1)引用被创建的同时必须被初始化(指针则可以在任何时候被初始化)。

    (2)不能有NULL 引用,引用必须与合法的存储单元关联(指针则可以是NULL)。

    (3)一旦引用被初始化,就不能改变引用的关系(指针则可以随时改变所指的对象)。


三、浅拷贝和深拷贝

如果类没有自定义拷贝构造函数,C++编译器自动会产生一个默认的拷贝构造函数。这个默认的拷贝构造函数采用的是“位拷贝”(浅拷贝),而非“值拷贝”(深拷贝)的方式,如果类中含有指针变量,默认的拷贝构造函数必定出错。

四、开多少线程最优

这个有共识的和CPU核数有关。一般控制到CPU核数的1-2倍。

五、观察者模式

Observer 模式应该可以说是应用最多、影响最广的模式之一。Observer 模式要解决的问题为: 建立一个一( Subject)对多( Observer) 的依赖关系, 并且做到当“一” 变化的时候, 依赖这个“一”的多也能够同步改变。MVC就是一个Observer的实例。


应用场景: 对同一组数据进行统计分析时候, 我们希望能够提供多种形式的表示 (例如以表格进行统计显示、柱状图统计显示、百分比统计显示等)。这些表示都依赖于同一组数据, 我们当然需要当数据改变的时候, 所有的统计的显示都能够同时改变。 Observer 模式就是解决了这一个问题。


UML类图:

Subject(目标,这个只有一个)
——目标知道它的观察者。可以有任意多个观察者观察同一个目标;
——提供注册和删除观察者对象的接口。

Observer(观察者,可以有很多个)
——为那些在目标发生改变时需获得通知的对象定义一个更新接口。

ConcreteSubject(具体目标)
——将有关状态存入各ConcreteObserver对象;
——当它的状态发生改变时,向它的各个观察者发出通知。

ConcreteObserver(具体观察者)
——维护一个指向ConcreteSubject对象的引用;
——存储有关状态,这些状态应与目标的状态保持一致;
——实现Observer的更新接口,先通过ConcreteSubject获取目标的状态,然后使自身状态与目标的状态保持一致。


代码实现:

#include <iostream>
#include <list>
using namespace std;

class CSubject;
//观察者的超类
class CObserver
{
public:
	virtual void setSubject(CSubject* psubject) = 0;
	virtual void Update(int status) = 0;
};

//目标的超类
class CSubject
{
public:
	virtual void Attach(CObserver* pobserver) = 0;
	virtual void Detach(CObserver* pobserver) = 0;
	virtual void Notify() = 0;
};

//具体的观察者
class CCocreateObserver :public CObserver
{
public:
	void setSubject(CSubject* psubject)
	{
		m_subject = psubject;
	};
	void Update(int status){
		cout<<"CCocreateObserver get the update, new status:"<<status<<endl;
	}
private:
	CSubject* m_subject;
};
class CCocreateObserver2 :public CObserver
{
public:
	void setSubject(CSubject* psubject)
	{
		m_subject = psubject;
	}
	void Update(int status)
	{
		cout<<"CCocreateObserver2 get the update, new status:"<<status<<endl;
	}
private:
	CSubject* m_subject;
};

//具体的目标
class CCocreateSubject:public CSubject
{
public:	
	void Attach(CObserver* pobserver)
	{
		m_listObsrver.push_back(pobserver);
		pobserver->setSubject(this);
	}
	void Detach(CObserver* pobserver)
	{
		m_listObsrver.remove(pobserver);
	}
	void Notify()
	{
		std::list<CObserver*>::iterator it = m_listObsrver.begin();
		while(it != m_listObsrver.end())
		{
			(*it)->Update(m_iStatus);
			it++;
		}
	}

	void SetState(int state)
	{
		m_iStatus= state;
	}
private:
	list<CObserver*> m_listObsrver;
	int m_iStatus;

};


int _tmain(int argc, _TCHAR* argv[])
{
    //创建目标
    CCocreateSubject *psubject = new CCocreateSubject();

    //创建观察者
    CCocreateObserver *pobserver = new CCocreateObserver();
    CCocreateObserver2 *pobserver2 = new CCocreateObserver2();

    //
    psubject->Attach(pobserver);
    psubject->Attach(pobserver2);

    //改变状态
    psubject->SetState(5);
    psubject->Notify();

    psubject->SetState(8);
    psubject->Notify();

    psubject->Detach(pobserver);
    psubject->Detach(pobserver2);

    delete pobserver;
    delete pobserver2;
    delete psubject;

    getchar();
}

输出结果:






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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值