浅笑博客
魔装少女就是本少爷!
浅笑博客
学习随笔0526
学习随笔0526

1.C++的虚函数可以实现构造函数吗?

虚函数的作用是允许在派生类中重新定义与基类同名的函数,并且可以通过基类指针或引用来访问基类和派生类中的同名函数。

c++的虚函数是由虚函数实现,虚函数表在对象创建后才存在。

假设可以,创建对象时调用构造函数,由于时虚函数需要去虚函数表里找函数地址,没虚函数表。

关于虚函数的一个程序示例:

#include <stdio.h>  
#include <iostream>
using namespace std;

class Base {
public:
    virtual void f() { cout << "Base::f" << endl; }
    virtual void g() { cout << "Base::g" << endl; }
    virtual void h() { cout << "Base::h" << endl; }
};
class A:public Base{
public:
    A() = default;
    void f(){
        cout<<"A::f"<<endl;
    }
};

//定义一个无参返回值为空的函数指针
typedef void (*Fun) ();

int main() {
    Base b;
    Fun pFun = NULL;
    b.f();
    cout << "虚表指针:" << (int *)&b << endl;//对象最前面是虚表指针,指向虚函数表
    //虚表指针指向虚函数表
    cout << "虚函数表 — 第一个函数地址:" << (int*)*(int*)(&b) << endl;
    pFun = (Fun)*((int*)*(int*)(&b)+1);
    pFun();//调用Base中第二个函数g()
    A a;
    a.f();
    Base *base = &a;
    base->f();
    return 0;
} 

输出:

Base::f
虚表指针:0x61ff04
虚函数表 — 第一个函数地址:0x4051d0
Base::g
A::f
A::f

2.C++的析构函数可以是虚函数吗?

析构函数作用:在对象消亡时,自动被调用,用来释放对象占用的空间。

因为是在对象消亡时才调用,即对象已被创建,存在虚函数表,所以可以。

而且C++实际开发应用中,通常会用父类指针指向子类对象,所以析构函数常常被定义为虚函数,以能够正确识别对象类型及正确销毁对象。

#include <stdio.h>  
#include <iostream>
using namespace std;

class Base {
public:
    virtual ~Base(){cout << "~Base()" << endl;}
    virtual void f() { cout << "Base::f" << endl; }
};
class A:public Base{
public:
    ~A(){
        cout << "~A()" << endl;
    }
    A() = default;
    void f(){
        cout<<"A::f"<<endl;
    }
};

int main() {
    Base *base = new A;
    base->f();
    delete base;
    return 0;
} 

输出:

A::f
~A()
~Base()

3.这段程序有什么问题?

class C {
    public:             
    void func(int a) {
        printf("hello:%d",a);
    }
};
int main() {
    C *c = NULL;
    c->func(1);
    return 0;
} 

没问题。

#include <stdio.h>  
#include <iostream>
using namespace std;

class C {
public:
    int a = 0;
    virtual ~C(){cout << "~Base()" << endl;}
    virtual void f() { cout << "Base::f" << endl; }
    void g(){cout << "Base:g" << endl;}
    void h(){cout << a << endl;}
};
int main() {
    C *p = NULL;
    p->g();//正常调用
    p->h();//调用的函数不能引用this.a
    p->f();//不能调用虚函数
    return 0;
} 

1).为什么可以调用成员函数?

对于类成员函数而言,并不是一个对象对应一个单独的成员函数体,而是此类的所有对象共用这个成员函数体。 当程序被编译之后,此成员函数地址即已确定。当调用p->func1(); 这句话时,其实就是调用A::func1(this);而成员函数的地址在编译时就已经确定, 需要注意的是,你用空指针调用成员函数,只是让this指针指向了空,所以空指针也是可以调用普通成员函数,只不过此时的this指针指向空而已,但函数fun1函数体内并没有用到this指针,所以不会出现问题。[本段摘自CSDN博主「shanghx_123」的原创文章( https://blog.csdn.net/shanghx_123/java/article/details/89744613 )]。

2).为什么不能调用h()?

因为是空指针调用,this指向空,this.a报错(编译器不知道a是哪个对象的)。

3).为什么不可以调用虚函数?

用空指针调用,指针找不到对应对象的地址,所以找不到虚函数表,所以不行。

4.java面向对象的特性?

1).封装:

将类的某些信息隐藏在类内部,不允许外部程序直接访问,而是通过该类提供的方法来实现对隐藏信息的操作和访问。

封装比较好理解,多的就不说了。

说下访控符的区别:

访控符本类同包子类其他
private
默认
protected
public

内部类:

即定义在另外一个类里面的类。以提供更好的封装,更方便。

有成员内部类、静态内部类、方法内部类、匿名内部类。(可参考https://www.cnblogs.com/hysum/p/7101974.html 具体学习)

2).继承

继承是类与类的一种关系 。java中的继承是单继承,即一个类只有一个父类。子类拥有父类除private访控的所有属性和方法以实现了代码的复用。

重载和重写的区别:

方法重载:同一个类中处理不同数据的多个相同方法名的多态手段。

方法重写:继承中,子类可对父类的方法进行重新定义(方法名、参数类型个数、返回值类型都要相同)。

初始化一个子类的过程:

父类对象属性初始化->父类构造->子类对象属性初始化->子类构造

3).多态

简而言之,多态即对象的多种形态。一种多态指同一方法名可以有不同类型、个数参数的一种表现(重载),这其实仅仅是指编译时期的多态(静态多态)。还有一种多态是指运行时的多态,即允许不同类的对象对同一消息做出不同的响应,如继承中对父类方法的重写后父类引用指向子类对象调用重写的方法、接口的实现中同一接口的不同类对接口内同一方法进行不同的实现后使用接口引用调用方法都是多态的表现。

多态(运行时多态)存在的3个条件:继承、重写、父类引用指向子类对象。

其实多态在实际开发中应用很多,可以理解继承是多态的基础。多态使代码具有可替换性、可扩充性、接口性、更好的灵活性、简化性。

5.java垃圾回收机制

简称GC,即 Garbage Collection。是java语言不同于c++的一个重要区别。在Java中,程序员不需要去关心内存动态分配和垃圾回收的问题,这一切都交给了JVM来处理。

什么样的对象是垃圾?

对于Java对象来讲,如果说这个对象没有被其他对象所引用该对象就是无用的,被称为垃圾,其占用的内存也就要被销毁。多我来讲,还有一种对象不是垃圾,那就是女朋友。

标记垃圾的算法:引用计数法、可达性分析算法。

垃圾回收算法:标记清除算法、复制算法、标记整理算法、分代回收算法。

6.进程于线程的区别联系。

参考:https://blog.csdn.net/jeromezmzx007/article/details/90711743

进程是具有一定独立功能的程序关于某个数据集合上的一次运行活动,是系统进行资源分配和调度的一个独立单位。

线程是进程的一个实体,是CPU调度和分派的基本单位,他是比进程更小的能独立运行的基本单位,一个线程可以创建和撤销另一个线程。

进程和线程的关系
(1)一个线程只能属于一个进程,而一个进程可以有多个线程,但至少有一个线程。
(2)资源分配给进程,同一进程的所有线程共享该进程的所有资源。
(3)线程在执行过程中,需要协作同步。不同进程的线程间要利用消息通信的办法实现同步。
(4)处理机分给线程,即真正在处理机上运行的是线程
(5)线程是指进程内的一个执行单元,也是进程内的可调度实体。

线程与进程的区别
(1)调度:线程作为调度和分配的基本单位,进程作为拥有资源的基本单位。
(2)并发性:不仅进程之间可以并发执行,同一个进程的多个线程之间也可以并发执行。线程的划分尺度小于进程,使得多线程程序的并发性高。
(3)拥有资源:进程是拥有资源的一个独立单位,线程不拥有系统资源,但可以访问隶属于进程的资源。
(4)系统开销:在创建或撤销进程的时候,由于系统都要为之分配和回收资源,导致系统创建或撤销进程的开销明显大于创建或撤销线程时的开销。但进程有独立的地址空间,进程崩溃后,在保护模式下不会对其他的进程产生影响,而线程只是一个进程中的不同的执行路径线程有自己的堆栈和局部变量,但线程之间没有单独的地址空间,一个线程死掉就等于整个进程死掉,所以多进程的程序要比多线程的程序健壮,但是在进程切换时,耗费的资源较大,效率要差些。
(5)执行过程: 进程在执行过程中拥有独立的内存单元,而多个线程共享内存,从而极大的提高了程序运行效率。 线程在执行过程中,每个独立的线程有一个程序运行的入口,顺序执行序列和程序的出口。但是线程不能够独立执行,必须依存在应用程序中,有应用程序提供多个线程执行控制。
(6)从逻辑角度看,多线程的意义在于一个应用程序中,有多个执行部分可以同时执行。但操作系统并没有将多个线程看做多个独立的应用,来实现进程的调度和管理以及资源分配。

7.进程通信

参考:https://www.cnblogs.com/fmqdblog/p/10680077.html

进程通信:管道(pipe)、命名管道(named pipe/FIFO)、信号量(semophonre)、消息队列(message queue)、信号(sinal)、共享内存(shared memory)、套接字(socket)、全双工管道。

线程通信:锁机制(包括互斥锁、条件变量、读写锁)、信号量机制(Semaphore)、信号机制(Signal)。

8.为什么使用多线程?

1). 花销小,切换快
2). 方便的通信机制
3).减少耗时,提高响应速度
4).提高CPU利用率
5).改善程序结构

9.编译原理过程

词法分析、语法分析、语义分析、中间代码生成、独立于机器的代码优化、代码生成、以来机器的代码优化。

http://blog.qianxiao.fun/wp-content/uploads/2020/05/图片-4-1024x576.png

10.http与https

http(超文本传输协议),连接简单,无状态,应用层的协议,常基于TCP/IP协议传输数据,互联网上应用最为广泛的一种网络协议。https (安全超文本传输协议) ,使用ssl加密数据进行传输,提供身份认证,使传输变得更安全。

http不安全,https安全。http端口80,https端口443。http工作在应用层,https工作在传输层。http无需证书,https需要证书。

11.get请求和post请求

GET和POST是HTTP(超文本传输协议)最常用的两种方法。get请求简单高效,将参数跟在url地址后面即可,但提交数据长度有限。post请求更安全(get中由于参数即在url中,可能暴露敏感信息),请求参数放在 Request body 中,提交数据长度无限制。这里只列出主要区别更多区别可参考百度。

12.安卓中Handle类实现内部类会造成内存泄漏的问题

参考:https://blog.csdn.net/suyimin2010/article/details/81144110

所谓内存泄露,可以理解为垃圾没有被及时回收。在Java中,非静态的内部类或者匿名类会隐式的持有其外部类的引用,而静态的内部类则不会。如下例:

public class MainActivity extends Activity {
 
  private final Handler mLeakyHandler = new Handler() {
    @Override
    public void handleMessage(Message msg) {
      //...
    }
  }
 
  @Override
  protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    mLeakyHandler.postDelayed(new Runnable() {
      @Override
      public void run() { //... }
    }, 5000);
    finish();
  }
}

当activity被finish的时候,延迟发送的消息仍然会存活在UI线程的消息队列中,直到延迟事件到后它才被处理。这个消息持有activity的Handler的引用,Handler又隐式的持有它的外部类(MainActivity)的引用。这个引用会一直存在直到这个消息被处理,所以垃圾回收机制就没法回收这个activity,内存泄露就发生了。非静态的匿名类也会隐式的持有外部类的引用,所以context会被泄露掉。

13.C++编译的so文件的格式是什么?

参考:https://www.jianshu.com/p/ef462437b999

so文件即库文件,通常我们称之为so库,通常在android ndk开发中使用C/C++实现编译生成以java层调用(JNI)运行在android。

so文件格式即ELF格式(可执行链接格式),是Linux下可执行文件。有多个段组成,每个段有不同的权限,名称。主要有ELF头、程序头、不同的节区、字符串表组成。

发表评论

textsms
account_circle
email

浅笑博客

学习随笔0526
1.C++的虚函数可以实现构造函数吗? 虚函数的作用是允许在派生类中重新定义与基类同名的函数,并且可以通过基类指针或引用来访问基类和派生类中的同名函数。 c++的虚函数是由虚函…
扫描二维码继续阅读
2020-05-26