C++学习(59)

1. char a[5],*p=a;以下说法正确的是 A

A p=”abcd”  Ba=”abcd”;    C *p=”abcd”;   D *a=”abcd”

分析:p里面存的是数组a的首元素的地址,p是一个指针变量,指向字符型数据,指向字符变量,不是把“abcd”这些字符存放到p中,也不是把字符串赋给*p,只是把“abcd”的第一个字符的地址赋给指针变量p。

 

2. 指针变量的值是指指针所指向的变量在内存中的地址。(正确)


3. 下面代码输出结果是

int main() {
   intpid;
   intnum=1;
   pid=fork();
   if(pid>0){
      num++;
      printf("inparent:num:%d addr:%x\n",num,&num);
   }
   elseif(pid==0) {
      printf("inchild:num:%d addr:%x\n",num,&num);
   }
}


B、父子进程中输出的num不同,num地址相同。

分析:虚拟地址空间。num地址的值相同,但是其真实的物理地址却不一样。 linux下实现了一下,发现地址值真的一样。 fork之后子进程复制了父进程的数据、堆栈。但是由于地址重定位器之类的魔法存在, 所以,看似一样的地址空间(虚拟地址空间), 其实却是不同的物理地址空间。 同时可以验证c程序中输出的地址空间其实都是虚拟地址空间。

 

分析二:

fork()之后,操作系统会复制一个与父进程完全相同的子进程,虽说是父子关系,但是在操作系统看来,他们更像兄弟关系,这2个进程共享代码空间,但是数据空间是互相独立的,子进程数据空间中的内容是父进程的完整拷贝,指令指针也完全相同,但只有一点不同,如果fork成功,子进程中fork的返回值是0,父进程中fork的返回值是子进程的进程号,如果fork不成功,父进程会返回错误。可以这样想象,2个进程一直同时运行,而且步调一致,在fork之后,他们分别作不同的工作,也就是分岔了。这也是fork为什么叫fork的原因。

 

勘误:子进程的pid是0,子进程的getpid()是它自己的进程号;父进程中的pid值为子进程进程号,只有父进程执行的getpid()才是他自己的进程号。

4. 下面说法正确的是(A

A 一个空类默认一定生成构造函数,拷贝构造函数,赋值操作符,引用操作符,析构函数。

B可以有多个析构函数

C 析构函数可以为virtual,可以被重载

D 类的构造函数如果都不是public访问属性,则类的实例无法创建

分析:C析构函数没有参数列表,无法重载,但可以重写

D单列模式下,成员函数私有可以实例化。

 单例模式也称为单件模式、单子模式,可能是使用最广泛的设计模式。其意图是保证一个类仅有一个实例,并提供一个访问它的全局访问点,该实例被所有程序模块共享。

单例模式有许多种实现方法,在C++中,甚至可以直接用一个全局变量做到这一点,但这样的代码显的很不优雅。使用全局对象能够保证方便地访问实例,但是不能保证只声明一个对象——也就是说除了一个全局实例外,仍然能创建相同类的本地实例。

《设计模式》一书中给出了一种很不错的实现,定义一个单例类,使用类的私有静态指针变量指向类的唯一实例,并用一个公有的静态方法获取该实例。

单例模式通过类本身来管理其唯一实例,这种特性提供了解决问题的方法。唯一的实例是类的一个普通对象,但设计这个类时,让它只能创建一个实例并提供对此实例的全局访问。唯一实例类Singleton在静态成员函数中隐藏创建实例的操作。习惯上把这个成员函数叫做Instance(),它的返回值是唯一实例的指针。

用户访问唯一实例的方法只有GetInstance()成员函数。如果不通过这个函数,任何创建实例的尝试都将失败,因为类的构造函数是私有的。GetInstance()使用 懒惰初始化,也就是说它的返回值是当这个函数首次被访问时被创建的 。这是一种防弹设计——所有GetInstance()之后的调用都返回相同实例的指针。

 

5. 分析下述代码

#include<iostream>
using namespace std;
int main() {
   inta[2][5]={{2,3,4,5,6},{7,8,9,10,11}};
   int*ptr=(int *)(&a+1);
   cout<<*(ptr-3)<<endl;
   return0;
}

分析:数组名是数组这种类型的变量名,所以对数组名取地址是取的整个数组的地址,所以&a+1自然要跨过整个数组的长度,本题即跨过2*5 = 10个int的长度。

有了上述概念,再来分析这道题,int *ptr = (int*)(&a+1),p此时指向的地址应该是a[1][4]后面的地址,由于ptr是int型指针,ptr-3应该是ptr向前移动3个元素,即ptr-3指向a[1][2],所以*(ptr -3) = 9

 

#include<iostream>
using namespace std;
int main() {
   inta[][5]={{2,3,4,5,6},{7,8,9,10,11},{12,13,14,15,16}};
   int*p=(int *)(&a+1);
   int*p2=(int *)(a+1);
   int*p3=(int *)(a[0]+1);
   cout<<*(p-3)<<""<<*p2<<" "<<*p3<<endl;
   return0;
}

输出 14 7 3

分析:a是数组首地址,也就是a[0]的地址;&a是对象(数组)首地址,a+1是数组下一元素的地址,即a[1]&a+1是下一个对象的地址。

 

6. 如果类的定义如下,则以下代码正确并且良好编程风格是的:

class Object{

   public:

      virtual~Object(){}

      //

};

A std::auto_ptr<Object> pObj(newObject);

解释:

1) auto_ptr的意义

std::auto_ptr是C++标准库里面的模版类, 属于智能指针.当系统异常退出的时候避免资源泄漏(内存)。 其他的资源还对应其他的智能指针。

2) auto_ptr的使用

std::auto_ptr<int> test(new int(1));

test将是一个auto_ptr的对象,使用一个int指针进行初始化。 

test可以象其他指针一样使用,如使用* 使用->但是++不可以使用,以后也许会扩展,其实难对++做越界管理,也许可以放弃一些速度。 当使用auto_ptr的时候,必须使用显式的类型转化来初始化,如auto_ptr<classA> a(new classA)而不能使用auto_ptr<classA>a = new classA;

3) auto_ptr所有权的转移

auto_ptr对所有权有严格的约定,一个auto_ptr只能控制一个指针,不能控制多个,当auto_ptr拥有一个指针的时候就不能在拥有其他的指针了。同时,不同的auto_ptr不能拥有同一个指针。

 

7. 三个基本元素:

1). 封装:封装是把过程和数据包围起来,对数据的访问只能通过已定义的界面。面向对象计算始于这个基本概念,即现实世界可以被描绘成一系列完全自治、封装的对象,这些对象通过一个受保护的接口访问其他对象。

2). 继承:继承是一种联结类的层次模型,并且允许和鼓励类的重用,它提供了一种明确表述共性的方法。对象的一个新类可以从现有的类中派生,这个过程称为类继承。新类继承了原始类的特性,新类称为原始类的派生类(子类),而原始类称为新类的基类(父类)。派生类可以从它的基类那里继承方法和实例变量,并且类可以修改或增加新的方法使之更适合特殊的需要。

3). 多态:多态性是指允许不同类的对象对同一消息作出响应。多态性包括参数化多态性和包含多态性。多态性语言具有灵活、抽象、行为共享、代码共享的优势,很好的解决了应用程序函数同名问题。

 

C++ 中的虚函数的作用主要是实现了多态的机制。关于多态,简而言之就是用父类型别的指针指向其子类的实例,然后通过父类的指针调用实际子类的成员函数。这种技术可以让父类的指针有“多种形态”,这是一种泛型技术。所谓泛型技术,说白了就是试图使用不变的代码来实现可变的算法。比如:模板技术, RTTI 技术,虚函数技术,要么是试图做到在编译时决议,要么试图做到运行时决议。

 

 

五个基本原则:

单一职责原则(Single-Resposibility Principle):一个类,最好只做一件事,只有一个引起它的变化。单一职责原则可以看做是低耦合、高内聚在面向对象原则上的引申,将职责定义为引起变化的原因,以提高内聚性来减少引起变化的原因。

开放封闭原则(Open-Closed principle):软件实体应该是可扩展的,而不可修改的。也就是,对扩展开放,对修改封闭的

Liskov替换原则(Liskov-SubstituionPrinciple):子类必须能够替换其基类。这一思想体现为对继承机制的约束规范,只有子类能够替换基类时,才能保证系统在运行期内识别子类,这是保证继承复用的基础。

依赖倒置原则(Dependecy-Inversion Principle):依赖于抽象。具体而言就是高层模块不依赖于底层模块,二者都同依赖于抽象;抽象不依赖于具体,具体依赖于抽象

接口隔离原则(Interface-Segregation Principle):使用多个小的专门的接口,而不要使用一个大的总接口。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值