当前位置:首页 » 编程软件 » 编译器继承

编译器继承

发布时间: 2022-05-31 04:45:57

‘壹’ include的作用与继承一样么

include的作用与继承完全不同。

include是插入文本的意思。也就是有一篇文字的东西写在另一个文件里,告诉编译器:在include的位置,插入该文件文字内容后再开始编译。

通常插入的东西是“头文件”,文件扩展名.h, 但实际上,插入别的也可以,例如xxx.c 也可以。不信,你试试简单的例子:
现有程序 b.c
写一个新程序 a.c
a.c 的内容就写一行:
#include "b.c"
编译a.c并运行a.exe,所得结果与b.c一样吧!

继承,不是文本(文字)的承继,而是含义的继承,它是在编译(翻译)和链接过程中发生的事。例如,你定义了一新类,并声明它继承CWin类,这样一来,所有CWin的成员变量,成员函数都自动变成你的新类的成员变量,成员函数,(如果你重新声明了某个变或函数,则以重写的为准)。

‘贰’ 关于继承中的构造方法

这句话是对的,不过要加个前提条件.那就是"在子类对象的构造过程中"

这就能很好解释一楼为什么说后半句是错的了,因为一楼没有创建子类对象,也就是没有new,当然也就不会涉及构造方法,所以他认为后半句是错的.实际上,这句话是对的,不过楼主应该加上"在子类对象的构造过程中" 这句话,而且整个这段话(也就是你问的),出现在马士兵老师讲课的视频中,一字不差,是对的.

另外,如果当用户没有定义构造方法时,编译器会为类自动添加形如类名() { } 的无参构造方法,但是一但自己定义了构造 方法,编译器将不再自动添加.

也就是说构造方法不是必须有的.如果你之前一直未自定义构造方法,当你new一个对象时,系统会自动调用默认的一个无参构造方法,给你对象的实例变量赋初值,比如int型默认为0.但一旦你自己定义了构造方法并new一个对象后,你再new一个对象时系统将不再为你自动提供默认的无参构造方法,那么你必须自己定义一个构造方法,否则编译出错

‘叁’ C++继承的构造顺序

1.构造函数
先看下面的类定义
class
B1 class B2
{ {
public: public:
int
i; int i;
B1() { i = 0;
} B2() { i = 0; }
virtual void f()
{} virtual void f() {}
}
; } ;

class
M1 class M2
{ {
public: public:
int
i; int i;
M1() { i = 0;
} M2() { i = 0; }
virtual void mf()
{} virtual void mf() {}
}
; };

class C : public B1, public B2
{
public:
virtual void f() {}
M1 m1;
M2 m2;
};

(1)编译器会不会为C生成默认构造(default ctor)
编译器只在需要时才会为一个类生成def
ctor。“需要时”指:
a.一个类有虚函数
b.一个类有虚基类
c.一个类的基类有def ctor
d.一个类的成员类有def ctor
在这里,class C符合c,d两个条件,编译器会为它生成def
ctor.

(2)默认构造的内容
编译器生成的def ctor是这样的
C::C()
{
B1::B1()
B2::B2()
设定虚表指针指向C的虚表
m1::M1()
m2::M2()
}
a.按声明顺序构造基类
b.设定虚表指针
c.按声明顺序构造成员类

(3)对自定义构造函数的改造
对于B1,B2,M1,M2,已有构造函数,但编译器会对其改造,加入一些代码,完成必要的初始化工作。改造后的ctor如下:(以B1为例)
B1::B1()
{
设定虚表指针指向B1的虚表
i = 0;
}
a.设定虚表指针
b.如果用户写有代码(如i=0),则执行这些代码

(4)综合(2),(3),构造函数完整代码如下
T::T()
{
按声明顺序构造基类
设定虚表指针
按声明顺序构造成员类
如果用户写有代码,则执行这些代码
}
在用户代码执行前,基类与成员类已构造完毕,虚指针已设定。

所以C的构造顺序是:B1-〉B2-〉虚指针设定-〉m1-〉m2->C自己的代码(如果有的话)
由(3)可知,每个类的ctor中,都会暂时将虚指针指向自己的虚表。调用B1::B1时,虚指针指向B1的虚表,然后在C::C中,虚指针被重新设定为C的虚表。
在继承体系中,构造是由上而下的,B1或B2构造时,C还未构造。C构造时,B1和B2已构造完成。

所以在继承体系中,一个类的构造函数执行时,该类的所有基类已构造完毕,虚指针已设定,所有成员类也已构造完毕。但该类的所有子类均未构造完成。

2.析构函数
(1)编译器会不会为C生成析构函数(dtor)
编译器只在需要时才会为一个类生成dtor。“需要时”指:
a.类的基类有析构
b.类的成员类有析构
与构造不同,少了两点,因为在一个类析构时,这是一个破坏操作(destory),既然类以已经没用了,何必再把虚指针设一下呢。

(2)析构的内容
编译器生成的析构是这样的
C::~C()
{
m2::M2()
m1::M1()
B2::B2()
B1::B1()
}
a.按声明顺序相反的顺序析构成员类
b.按声明顺序相反的顺序析构基类
这里的相反顺序是C++标准规定的要求,不同编译器都应做到,否则不符合标准(实际上编译器或多或少都有不符标准的地方,当然不是指这里所说的顺序问题)

(3)完整的析构的调用顺序
对于已有析构函数的类,编译器会对其改造,加入一些代码,完成必要的工作。改造后的dtor如下:
T::~T()
{
设定虚表指针指向T的虚表
执行用户代码
按声明顺序相反的顺序析构成员类
按声明顺序相反的顺序析构基类
}
这是完整的析构的调用顺序
在用户代码执行前,虚指针已重新设定,以便用户代码能正确执行。然后再析构成员类和基类。

所以,如果上面例子中的五个类都有析构函数的话,调用顺序是:
虚指针设定-〉C自己的代码->m2-〉m1-〉B2-〉B1
每个类的dtor中,都会暂时将虚指针指向自己的虚表。调用C::~C时,虚指针指向C的虚表,然后在B1::~B1中,虚指针被重新设定为B1的虚表。

可见,在继承体系中,析构是由下而上的,B1或B2析构时,C已被析构。C析构时,B1和B2还未被析构。
所以在继承体系中,一个类的析构函数执行时,该类的所有基类还未被析构,所有成员类也未被析构。但该类的所有子类均已析构完成。

3.虚函数
在构造或析构中调用虚函数,会怎样.如:
B1::B1()
{
f();
}
调用的是B1::f()还是C::f()
答案是B1::f()
每个类的ctor中,都会暂时将虚指针指向自己的虚表。调用B1::B1时,虚指针指向B1的虚表
所以是B1::f()
如果在C的构造函数中调用f(),那就调用C::f()

‘肆’ java面向对象关于继承的问题

Base base=new Child();
这个分为两部分。。Base base这是定义。。base=new Child();这是赋值。。
因为你把base定义为 Base类型。。所以编译器把他当做Base类型。。至于实际类型。。运行的时候才能确定。。所以不能访问Child的属性和方法。。

Child child=new Child();
Base child=new Child();
这个的不同应该明白了撒。。就是你写代码的时候。。编译器把他们看成的类型是不一样的。。

‘伍’ 继承了接口中的方法为什么编译器提示是错误的

你的接口的setFree和setPay方法漏了参数,而在继承后重写时又传入了double类型的值,当然会编译不通过。

‘陆’ 编译器和编程软件有什么区别啊

编译器就是将编程语言转化为机器语言的东东。
编程软件一般包含编译器。比如VS。

‘柒’ 初学c++类继承与派生的问题

简单地说,编译器生成代码的时候,该调用哪个成员函数是根据类型判断的,b的类型是基类指针,编译器就调用基类的成员函数fun1。为什么是这样呢?

因为继承关系下,编译器允许我们把子类当作基类用,这是合理的,也就是向上类型转换,把子类的信息全部丢弃(只是忽略,内存中还保留着,可以用静态转换static_cast转换回去,也就是向下类型转换),因此你把a的地址赋给b时,编译器把a当作基类用,当然应该和没有子类的情况一样,所以调用了基类的fun1。那如何才能根据实际的类型而不是先做向上转换来调用成员函数呢?

c++为了解决你这个问题,引入了多态,也就是虚函数,在成员函数定义前加上virtual。比如:
#include<iostream.h>
class BaseClass
{
public:
virtual void fun1(){cout<<"调用基类的fun1"<<endl;}
};
class DerivedClass:public BaseClass
{
public:
void fun1(){cout<<"调用派生类的fun1"<<endl;}//这里可以不加virtual,因为父类已经声明了,当然也可以加上,为了代码可读性
};
main()
{
DerivedClass a;
BaseClass*b=&a;
b->fun1();
}

为什么和不加virtual不一样呢?因为虚函数的入口存在了对象的内存空间,有一张虚函数表,调用的时候是去找表找到入口地址后调用,因此对象的内存是什么类型就会调用什么类型的虚函数,即使向上类型转换了,虚函数表也不会变,照样调用。

‘捌’ C++编程题 关于 继承和多态 的

首先你的第一个问题,d.vf2();这里涉及到一个c++的原则,子类有父类的同名函数,如果不是虚函数的话,则会“隐藏”父类的函数,不管参数是否一致,都会隐藏!所以你的dd::vf2(int
i)这个函数就把bb::vf2()隐藏了,因此dd就不会继承这个函数。至于为什么这么设计,以前貌似看某处b.s的访谈,说为了减小出错的几率,以免子类的使用者不小心误使用了父类的函数。
看起来貌似第二个问题和第一个问题是一样的,但是结果却不同,其实你应该去了解下c++的对象模型,你就知道它的运作机理了。
对于虚函数,是动态绑定的,在对象内部有一个虚函数表,表里面是一个个的函数指针,指向当前对象的各个虚函数真正的代码,当你代码执行到调用虚函数那里的时候,会去这个表里面查,然后取出函数指针再调用。
如果是非虚函数,则是静态绑定的,也就是说在编译的时候就已经确定要调用哪个函数!
不管b::vf2、d::vf2、d::vf3都是非虚函数,都会发生静态绑定。
也就是说编译器在编译代码的时候就会决定到底调用哪个函数。它怎么决定呢?看类型。如下:
bp->vf2();
//这句话,编译器看到了bp是b*类型的,于是就去找b::vf2()这个函数,找到了于是绑定成功。
d.vf2();
//这句话,编译器看到d是d类型的,于是去找d::vf2()这个函数,由于上面提到的隐藏原则,d不存在这个函数,于是没找到,出错。
dp->vf2();
//这句话,编译器看到dp是d*类型的,去找d::vf2()这个函数,于是同上,找不到,出错。
dp->vf3();//编译器看到dp是d*类型的,于是找d::vf3()这个函数,找到了,于是绑定成功。
分析完这四句编译器的行为,你就明白了吧。
我写这么多,你好歹多加点分吧……

‘玖’ C51是一种专为MCS-51系列单片机设计的高级语言C编译器,它继承了符合ANSI标准对吗

对的吧,虽然说具体概念好像是如此,但最主要的还是动手实践。我玩过很多次51单片机,编译器是基于C 语言的keil 4,挺好用的。

‘拾’ C++的继承机制

从语言和概念的角度来说,子类继承父类是继承了所有protected和public非static成员(static成员是共享而不是继承),而成员包括函数和数据。所以从概念上来说,成员函数和成员变量都被继承了。
从实现上来说,实现要在外显上不违反概念,在内部可以非常随意。所有的实现子类继承父类成员函数只是子类共享了父类的函数,没有两份拷贝。编译器知道父类的某成员函数的地址,那么在子类调用父类的该方法时,编译器只要产生
call 函数地址 的代码就可以调用父类的方法,完全没有必要保留两份拷贝。
换句话来说,非虚方法的调用在编译时就已经确定了,编译器掌握一切信息。编译器选择最高效的实现(只保留一份函数拷贝)来符合C++语言概念。从逻辑上认为子类继承了父类的方法。

对虚函数,如果是在子类对象上用.操作符调用虚函数,那么编译器可以确定函数地址,此时不需要使用虚函数调用机制。只有在基类指针上用->操作符调用虚函数时,才会使用虚函数调用机制。此时编译器不知道基类指针指向具体什么类型的对象,所以它不知道到底调用哪个函数,它产生类似如下代码:
call [vftable + functionoffset]
也就是通过虚函数表中对应函数偏移来调用,虚函数表的布局是编译器已知的。当具体某个对象构造时,他们初始化虚表使得其中指针都指向自己的虚函数。这样就通过这个实现来满足了C++的虚函数概念。

举个例子:
class base {
private:
int member1;
protected:
int member2;
public:
int fun();
virtual int virtualfun();
};

class derive : public base {
public:
int member;
public:
virtual int virtualfun();
};

在代码中使用:derive test;
(以微软c/c++编译器为例)那么test在内存中可能是如下布局:
110000 vftable----------->112000
110004 base::member1
110008 base::member2
11000c derive::member
----------------------------
112000 (vftable[0])derive::virtualfun------>410000
----------------------------
410000 int derive::virtualfun(){ ... }
410500 int base::virtualfun(){ ... }
411000 int base::fun(){ ... }

热点内容
java代码格式 发布:2024-05-21 21:56:09 浏览:35
吃奶算法 发布:2024-05-21 21:51:07 浏览:142
压缩机热泵 发布:2024-05-21 21:51:04 浏览:925
安卓网页源码在哪里 发布:2024-05-21 21:46:56 浏览:894
vbnet取网页源码 发布:2024-05-21 21:46:51 浏览:650
pythonospathwalk 发布:2024-05-21 21:46:42 浏览:552
网易我的世界服务器会不会很卡 发布:2024-05-21 21:46:03 浏览:55
电动汽车曾程器如何配置 发布:2024-05-21 21:45:52 浏览:609
服务器由什么控制 发布:2024-05-21 21:29:00 浏览:483
宁夏医科大学总医院oa服务器地址 发布:2024-05-21 20:05:27 浏览:848