tag 标签: virtual

相关博文
  • 热度 24
    2012-12-20 18:47
    3622 次阅读|
    0 个评论
    In my previous blogs, I've been explaining how virtual functions behave in C++ and how you can obtain similar behaviour in C. A few months ago, I showed how to emulate a polymorphic C++ class (a class with at least one virtual function) as a C structure that has an additional member commonly called a vptr (VEE-pointer). 1 The vptr points to a table of function pointers called a vtbl (VEE-table). The past two months, I showed how to initialise the vptr in base and derived class objects. 2, 3 This month, I'll explain the concept of pure virtual functions in C++. Although C doesn't provide native support for the concept, it's still applicable in C. As in my prior articles, my sample classes represent an assortment of two-dimensional geometric shapes such as circle, rectangle, and triangle, all derived from a common base class called shape. The type hierarchy looks like: The C++ definition for the shape base class looks in part like: class shape { shape(color o, color f); // constructor virtual double area() const; virtual double perimeter() const; ~~~ private: color outline, fill; }; and the definition for the circle class (derived from shape) looks like: class circle: public shape { public: circle(double r, color o, color f); // constructor virtual double area() const; virtual double perimeter() const; ~~~ private: double radius; }; The definition for the circle's area function is as you should expect: double circle::area() const { return pi * radius * radius; } The rectangle class derived from shape has members height and width instead of radius. The rectangle's area function is also as you should expect: double rectangle::area() const { return height * width; } What does shape's area function look like? For that matter, what's a shape that's neither a circle, nor a rectangle, nor any other type derived from base class shape? Remember, the shape class represents a common interface for all shapes. For example, you can define a C++ function: double volume(shape const *s, height h) { return s-area() * h; } which computes the volume of a solid with a base whose shape is s and whose height is h. You can then write: v = volume(c, 4.2); to compute the volume of a cylinder whose base is circle c and whose height is 4.2. Alternatively, you can define volume's parameter s as a reference instead of a pointer, as in: double volume(shape const s, height h) { return s.area() * h; } Then you don't need to take the address of volume's first argument explicitly, as in: v = volume(c, 4.2); You get the same result whether you use a pointer or a reference. With the hierarchy of shapes, it's meaningful to use a "pointer to shape" or a "reference to shape" to refer to a circle, rectangle, or triangle, or possibly some other shape that you might derive from the base class shape. It's also meaningful to have a shape object that's the base class part of some derived class object. However, it's not meaningful to have a shape object that's just a shape. A meaningful shape has a radius, or a height and a width, or some other attributes that define its physical extent. A shape that's just a shape has no such attributes. Nonetheless, declaring an area function in the shape class is a meaningful thing to do. That function declaration becomes part of the interface for every shape derived from the base class shape. That is, it's a way of forcing derived classes such as circle and rectangle to have an area function. Although declaring an area function for shape is meaningful, defining it is not because the base class lacks the attributes it needs to compute its area. Pure virtual functions provide a way to avoid defining such functions that have no meaningful implementation. In C++, you declare a virtual function as a pure virtual function simply by placing = 0 at the end of the function heading in the function declaration. For example, in: class shape { public: shape(color o, color f); // constructor virtual double area() const = 0; virtual double perimeter() const = 0; ~~~ private: color outline, fill; }; the area and perimeter functions are now pure virtual functions. You need not define them for class shape. If shape's area and perimeter functions are undefined, what happens when you try to call them? I'll explain that in my next column. I'll also look at what you have to do to approximate the same behaviour in C. Endnotes: 1. Saks, Dan, " Implementing Virtual functions in C ," Eetindia.co.in, August 14, 2012. 2. Saks, Dan, " How to properly initialise polymorphic objects ," Eetindia.co.in, October 25, 2012. 3. Saks, Dan, " Learn to Initialise derived polymorphic objects ," Eetindia.co.in, November 22, 2012.  
  • 热度 24
    2012-11-22 20:57
    3048 次阅读|
    1 个评论
    I have previously discussed polymorphic types and virtual functions. I showed how to implement virtual functions in C in a way that generates machine code similar to what you get with virtual function in C++.More specifically, I showed how to emulate a polymorphic C++ class (a class with at least one virtual function) as a C structure that has an additional member commonly called a vptr (VEE-pointer). The vptr points to a table of function pointers called a vtbl (VEE-table). Last month, I showed how to initialise the vptr in base class objects . This month, I'll look at initializing derived class objects. My sample classes represent an assortment of two-dimensional geometric shapes such as circle, rectangle, and triangle, all derived from a common base class called shape. The C++ definition for the shape base class looks in part like: class shape { public: shape(color o, color f); // constructor virtual double area() const; virtual double perimeter() const; private: color outline, fill; }; In C, the comparable declarations look like: // shape.h—a C base class for shapes #ifndef SHAPE_H_INCLUDED #define SHAPE_H_INCLUDED typedef struct shape shape; typedef struct shape_vtbl shape_vtbl; struct shape_vtbl { double (*area)(shape const *s); double (*perimeter)(shape const *s); }; struct shape { shape_vtbl *vptr; color outline, fill; }; void shape_construct(shape *s, color o, color f); double shape_area(shape const *s); double shape_perimeter(shape const *s); #endif As I showed last month, you can define the shape vtbl object in a source file that also defines the member functions of the shape "class": // shape.c—a C base class for shapes #include "shape.h" ~~~ static shape_vtbl the_shape_vtbl = { shape_area, shape_perimeter }; void shape_construct(shape *s, color o, color f) { s-vptr = the_shape_vtbl; s-outline = o; s-fill = f; } In C++, the definition for a circle class derived from shape looks like: class circle: public shape { public: circle(double r, color o, color f); // constructor virtual double area() const; virtual double perimeter() const; ~~~ private: double radius; }; Derivation defines an "is a" or "is a kind of" relationship between the derived and base class. That is, it lets you substitute a derived class object, such as a circle or rectangle, for a base class shape object. For example, given a C++ function such as: void f(shape *p) { ~~~ p-perimeter(); // virtual call to shape's perimeter ~~~ } you can pass it a derived class object, as in: circle c; ~~~ f(c); // pass a circle as a shape and it computes the circle's perimeter correctly. With a little more effort, you can emulate this behaviour in C. In C, you have to explicitly mention the vptr in virtual function calls, as in: void f(shape *p) { ~~~ p-vptr-perimeter(p); virtual call to shape's perimeter ~~~ } You also need an explicit cast to convert a "pointer to derived" into "pointer to base", as in: circle c; ~~~ f((shape *)c); // pass a circle as a shape This substitution works (f will compute the circle's perimeter correctly) only if the vptr has the same offset in the derived class object as it does in a base class object. The easiest way to satisfy this requirement is to implement each derived class type in C as a structure whose first member has the base class type, as in: // circle.h – a C class for circle derived from shape #ifndef CIRCLE_H_INCLUDED #define CIRCLE_H_INCLUDED #include "shape.h" typedef struct circle circle; struct circle { shape base; // the base class subobject double radius; }; void circle_construct(circle *c, double r, color o, color f); #endif The base member of the circle structure above includes all the members inherited from the shape base class, including vptr. The definition for the circle_construct function appears, along with the circle vtbl object, in a separate source file: // circle.c—circle implementation ~~~ #include "circle.h" double circle_area(circle const *c) { return PI * c-radius * c-radius; } double circle_perimeter(circle const *c) { return 2 * PI * c-radius; } typedef struct circle_vtbl circle_vtbl; struct circle_vtbl { double (*area)(circle const *); double (*perimeter)(circle const *); }; static circle_vtbl the_circle_vtbl = { circle_area, circle_perimeter }; void circle_construct(circle *c, double r, color o, color f) { shape_construct(c-base, o, f); c-base.vptr = (shape_vtbl *)the_circle_vtbl; c-radius = r; } The circle_construct function implements behaviour comparable to a C++ constructor. It calls the shape_construct function to initialise the base class part. However, shape_construct sets the vptr to point to shape's vtbl, which is correct for the base class shape, but not for the derived class circle. Thus, circle_construct needs to reassign the vptr to point to circle's vtbl. This assignment requires a cast because circle_vtbl isn't exactly the same type as shape_vtbl. The two structures have the same memory layout, but the corresponding pointers in the different structures point to functions with slightly different types. Thus, the derived class constructor contains two assignments to the vptr. The second assignment completely overwrites the value assigned by the first. Ideally, the compiler will "optimise away" the first assignment. However, the compiler can do this optimisation only if it can see both assignments in the context of the derived class constructor, which it can do only if the base class constructor is an inline function. If you define the shape_construct function as inline, you should move the function definition to the shape.h header file. When you do that, you must also give the_shape_vtbl external linkage by removing the keyword static from its definition, as in: // shape.c—a C base class for shapes ~~~ shape_vtbl the_shape_vtbl = { // used to be static shape_area, shape_perimeter }; ~~~ If your C compiler supports the inline keyword (from C99), then the shape.h header would look in part like: // shape.h—a C base class for shapes ~~~ typedef struct shape shape; ~~~ typedef struct shape_vtbl shape_vtbl; struct shape_vtbl { double (*area)(shape const *s); double (*perimeter)(shape const *s); }; extern shape_vtbl the_shape_vtbl; struct shape { shape_vtbl *vptr; color outline, fill; }; inline void shape_construct(shape *s, color o, color f) { s-vptr = the_shape_vtbl; s-outline = o; s-fill = f; } If your compiler doesn't support the keyword inline, then you can implement the constructor as a macro: #define shape_construct(s, o, f) ( \ (s)-vptr = the_shape_vtbl, \ (s)-outline = (o), \ (s)-fill = (f) \ ) Either way, a compiler with a decent optimiser should eliminate the redundant assignment to the vptr. Once again, you don't have to worry about any of this in C++. With C++, the compiler automatically generates code to initialise the vptr properly.  
  • 热度 22
    2012-8-14 13:49
    4167 次阅读|
    0 个评论
    Last month, I explained how C++ compilers typically implement virtual functions by illustrating how using virtual functions affects the storage layout for objects ( Setting storage layout for polymorphic objects ). This month, I'll continue by showing how to implement virtual functions in C in a way that generates machine code very similar to what you get from C++. As before, my sample classes represent an assortment of two-dimensional geometric shapes such as circle, rectangle, and triangle, all derived from a common base class called shape. In C++, the definition for the base class shape looks like: class shape { public: shape(); // constructor virtual double area() const; virtual double perimeter() const; private: coordinates position; color outline, fill; }; The area and perimeter member functions are virtual. A class, such as shape, with a least one virtual function is a polymorphic type . C++ compilers typically add a hidden pointer to each polymorphic type. That pointer is commonly called a vptr and it points to a table of function pointers called a vtbl . You can implement a polymorphic shape type in C using the following declarations: // shape.h—base class for shapes #ifndef SHAPE_H_INCLUDED #define SHAPE_H_INCLUDED typedef struct shape shape; typedef struct shape_vtbl shape_vtbl; struct shape_vtbl { double (*area)(shape const *s); double (*perimeter)(shape const *s); }; struct shape { shape_vtbl *vptr; coordinates position; color outline, fill; }; #endif A class derived from a polymorphic base class will be polymorphic as well, and it inherits the base class's vptr. The vptr must have the same offset in the base class subobject (the base class portion) of a derived class object as it does in a base class object. In C++, the definition for a circle class derived from shape looks like: class circle: public shape { public: circle(double r); // constructor virtual double area() const; virtual double perimeter() const; private: double radius; }; In C, the declarations for a polymorphic circle type look like: // circle.h – circle derived from shape #ifndef CIRCLE_H_INCLUDED #define CIRCLE_H_INCLUDED #include "shape.h" typedef struct circle circle; struct circle { shape base; // the base class sub-object double radius; }; void circle_construct(circle *c, double r); #endif The base member of the circle structure above includes all the members inherited from the shape base class, including vptr. The circle_construct function initializes a circle, including its vptr. I'll cover the details of initializing the vptr in an upcoming column. As I showed last month, the C++ definition for a rectangle class derived from shape looks a lot like the definition for circle: class rectangle: public shape { public: rectangle(double h, double w); virtual double area() const; virtual double perimeter() const; private: double height, width; }; Similarly, the C declarations for a polymorphic rectangle type look a lot like the declarations for circle: // rectangle.h—rectangle interface #ifndef RECTANGLE_H_INCLUDED #define RECTANGLE_H_INCLUDED #include "shape.h" typedef struct rectangle rectangle; struct rectangle { shape base; // the base class sub-object double height, width; }; void rectangle_construct(rectangle *t, double h, double w); #endif In C++, a call to the virtual area function applied to a shape looks exactly like a non-virtual call, as in: shape *s; ~~~ s-area(); If s points to a circle (the dynamic type of *s is circle), then the call above calls circle::area. If s points to a rectangle, then the call above calls rectangle::area. C doesn't provide explicit support for classes with member functions. In C, you simply use ordinary functions to emulate member functions. For example: circle_area(c); applies the circle_area function to circle c. You get the same runtime performance as a C++ member function call, but without any compile-time checking to enforce access control. In C, virtual function calls look unlike any other kind of function call. For example, a call to the virtual area function applied to a shape looks like: shape *s; ~~~ s-vptr-area(s); In this case, if s points to a circle (the dynamic type of *s is circle), then the call above calls circle_area. If s points to a rectangle, then the call above calls rectangle_area. As I hinted earlier, this works only if you initialise the vptr properly, something I'll cover in an upcoming column.  
  • 热度 18
    2012-4-20 19:37
    2050 次阅读|
    1 个评论
    总体实现的功能框图如下图所示:   图中的clock信号和复位信号没有画出。这个设计很简单,作为初学者的我,主要是学习熟悉一下Signal Tap II 和virtual pin 的使用。对于初学者来说,很多时间都花在软件使用上,而且很多资料都只是理论性的给出软件的优点、参数,很少给出具体的用法,所以只能看很多资料然后摸索吧。 这里测试的ADC芯片为AD9820。代码如下: module adc8test(clk,rst_n,adcin,adclk,adcout); input clk; input rst_n; output adclk; output adcout; input adcin; reg adcin_r; assign adclk = clk; assign adcout = adcin_r; always @(posedge clk or negedge rst_n) begin        if(!rst_n) adcin_r = 8'd0;        else               adcin_r = adcin; end endmodule 综合后的RTL视图如下所示: ADC模块数据输出引脚不需要输出到FPGA外部,只需供Signal Tap II采样,因此可以设定为Virtual Pin。代码写好后先初始编译,然后再分配管脚和Virtual Pin。 设定Virtual Pin:Virtual Pin的设置既可以采用输入TCL脚本的方式进行也可以在图形化界面操作,刚开始学习总是不太习惯TCL脚本,还是在图形化界面下操作吧。点击Assignment----Assignment Edit,如下所示:   按照上图所示的操作步骤选择需要设定Virtual Pin的端口,然后点击OK,出现下面示意图:   按照上图设定参数就OK了,然后点击保存从新编译。最后编译的结果如下图所示:   从编译结果中看到设定的Virtual Pin已经设置成功。 下面是设定Signal Tap II的过程: 点击File---new,选择如下图所示的文件:    然后出现下面的设置界面: 按照图中的步骤设置即可,在步骤4中需要双击空白处选择需要采样的数据节点。这里需要选择刚刚设定的Virtual Pin;Clock的选择通常选择系统时钟;Trigger Conditions选择Basic。其它的配置选择默认就可以了,具体每个选项的意义,以后再讨论。 最后将代码下载到FPGA中,然后点击Tools---Signal Tap II Logic Analyzer打开SignalTap II,出现下面的界面:     点击1或者2就可以采集到相应的数据,这里输入ADC的信号为1MHz的正弦信号,采样时钟为20MHz。在3处点击右键选择Bus Display Format选择显示数据的格式,这里选择的是Unsigned Line Char。
  • 热度 28
    2012-4-7 11:12
    2374 次阅读|
    0 个评论
    Over the past few years, I've written several articles about representing and manipulating memory-mapped devices in C and C++. Some readers commented that the C++ techniques I presented were lacking in that they failed to use more advanced features such as inheritance and virtual functions. Classes with virtual functions can be very useful, but they aren't the solution to every problem. Classes that represent memory-mapped devices, such as the ones I've presented, work with real hardware specifically because they don't use virtual functions. Last month (" Discriminated unions ," March 2012), I looked at the sort of problem that virtual functions are good at solving. I described a typical C solution using discriminated unions and discussed the limitations of that approach. This month, I'll explain how to use virtual functions in C++ to solve the same problem. In the not-too-distant future, I'll also show you how C++ typically implements virtual functions by showing how you can emulate them in C. Although my primary focus here is virtual functions, of necessity I'll discuss class derivation as well. However, I'll cover only those aspects of derivation that I need to explain virtual functions. Deriving a class The problem I presented last month involved representing a collection of two-dimensional geometric shapes such as circles, rectangles, and triangles. Each shape object contains some linear or angular distances sufficient to characterise the physical extent of the shape. For example, a circle has a radius, a rectangle has a height and a width, and a triangle has two sides and an angle. Each shape also had common attributes, such as position (planar coordinates), or outline and fill colours. In C++, you can represent the various shapes as a collection of classes. You start by defining a shape class which captures the properties common to all shapes: class shape { public: shape(); // constructor double area() const; double perimeter() const; ~~~ private: coordinates position; colour outline, fill; }; The class declares several functions as public members, including area and perimeter. The intent is that every shape—whether it's a circle, rectangle, triangle, or anything else—will provide these functions. In effect, class shape defines a common interface shared by every specific type of shape. The shape class also declares data members position, outline, and fill. The intent is that every shape object—no matter what kind of shape it is—will contain storage for these members. Now you can define classes for each specific shape by deriving them from class shape. For example, you can define the circle class as: class circle: public shape { public: circle(double r); // constructor double area() const; double perimeter() const; ~~~ private: double radius; }; In the class definition above, the class heading: class circle: public shape specifies that class circle is derived from class shape. The "derived from" class is commonly called the "base" class. The keyword public in the class heading indicates that the derivation is public. C++ also permits private and protected derivation, but I'm going to ignore those variants here, and make the simplifying assumption that all derivation is public. It's by far the most common usage. A derived class inherits all the data members of its base class. That is, the data members declared in the base class occupy storage in the derived class as well. Members declared private in the base class won't be accessible in the derived class, but they will still occupy storage in derived class objects. For example, the base class shape has three data members, declared as: coordinates position; colour outline, fill; The derived class circle declares one more data member: double radius; Thus, the data storage for a circle object is essentially the same as that of a structure defined as: struct circle { coordinates position; colour outline, fill; double radius; }; A derived class also inherits member functions from its base class. However, special member functions such as constructors, destructors, and copy assignment operators aren't inherited. If the circle class didn't declare area and perimeter as member functions, circle would inherit the functions exactly as they're defined in the shape base class. For example, I have yet to show the definition for shape's area functions, but whatever it is, it can't be right for circle. The problem is that a circle's area depends on its radius, but the radius data member is defined in class circle, not in class shape. Although a derived class may have access to data members inherited from a base class, a base class normally can't see the members declared in its derived classes. Thus, the shape class doesn't know that a circle has a radius. The definition for the circle's area function is very simple: double circle::area() const { return pi * radius * radius; } where pi is presumably a previously-defined constant representing Π. The keyword const appearing after the function parameter list indicates that area function treats each circle as a constant object. That is, computing the area of a circle doesn't alter the circle. A hierarchy of shapes You can easily create derived classes for additional shapes. For example, here are class definitions for rectangle: class rectangle: public shape { public: rectangle(double h, double w); double area() const; double perimeter() const; ~~~ private: double height, width; }; and for triangle: class triangle: public shape { public: triangle(double s1, double s2, double a); double area() const; double perimeter() const; ~~~ private: double side1, side2, angle; }; All of these shapes can be viewed as a hierarchy, typically drawn with the base class at the top, shown in Figure 1.   The base class doesn't know that it has any derived classes. Each derived class knows of its base class, but doesn't know about any of the other derived classes.  
相关资源
  • 所需E币: 1
    时间: 2022-7-23 12:41
    大小: 2.68MB
    上传者: Argent
    AnAOItoconvertmovementofVirtualAxisinrealmovement
  • 所需E币: 1
    时间: 2022-7-23 11:20
    大小: 3.14MB
    上传者: Argent
    ConvertingmovementofVirtualAxisinrealmovem
  • 所需E币: 1
    时间: 2022-6-20 01:35
    大小: 23.62MB
    上传者: qwhus_654232758
    虚拟现实佳作,作者为被脸书收购的Oculus首席科学家,UIUC教授。
  • 所需E币: 1
    时间: 2022-5-9 13:40
    大小: 3.29MB
    上传者: 西风瘦马
    VirtualRealityAugmentedRealityWhitePaper.pdf
  • 所需E币: 0
    时间: 2022-3-14 23:52
    大小: 2.8MB
    上传者: samewell
    虚拟现实技术(VirtualReality)简称VR技术课题演讲.pptx
  • 所需E币: 0
    时间: 2020-12-22 16:48
    大小: 742.18KB
    上传者: samewell
  • 所需E币: 4
    时间: 2019-12-24 23:11
    大小: 332.02KB
    上传者: givh79_163.com
    本文档介绍了如何使用LPC214X的USB端口设计一个虚拟的COM端口驱动程序。AN10420USBvirtualCOMportonLPC214xRev.01―04January2006ApplicationnoteDocumentinformationInfoContentKeywordsUSB,virtualCOMport,classdriver,Microcontroller,MCU,USBdevicerequest,USBresetphase,USBenumerationphase.AbstractThisdocumentdescribeshowtodesignavirtualCOMportdriverusingLPC214xUSBport.PhilipsSemiconductorsAN10420USBvirtualCOMportonLPC214xRevisionhistoryRevDateDescription0120060104I……
  • 所需E币: 3
    时间: 2019-12-24 17:08
    大小: 52.06KB
    上传者: 微风DS
    摘要:铁路分裂是一个人造的虚拟接地作为参考电压。它是用来设置信号匹配运算放大器的“甜蜜点”。运算放大器具有最线性,无失真的品质,甜蜜点。通常情况下,甜蜜点附近发生单电源轨和地面之间的中心。在信号的情况下,虚拟的地面控制复或开关信号时,通道的DC错误。Maxim>AppNotes>AudioCircuitsGeneralEngineeringTopicsPower-SupplyCircuitsKeywords:OpAmps,VirtualGround,RailSplitter,multiplexer,MUX,voltagedivider,sensorconditioning,Dec19,2008precisionresistor,digitalpots,potentiometer,resistance,singlepowersupply,center,matching-bias,reference,channeloffset,settlingtime,errorAPPLICATIONNOTE4344RailSplitter,fromAbrahamLincolntoVirtualGroundBy:BillLaumeisterAbstract:Railsplittingiscreatinganartificialvirtualgroundasareferencevoltage.Itisusedtosetthesignaltomatchtheopamp's"sweetspot."Anopamphasthemostlinear-anddistortion-freequalitiesatthatsweetspot.Typically,thesweetspotoccursnearthecenterbetweenthesinglepowerrailandground.Inthecase……
  • 所需E币: 5
    时间: 2020-1-13 16:10
    大小: 3.42MB
    上传者: 978461154_qq
    HFSS的几个PPT文档(FREE),Virtual_Prototyping_and_AutoModeling_for_Spiral_Inductor-7……
  • 所需E币: 4
    时间: 2019-12-20 16:52
    大小: 174.95KB
    上传者: 978461154_qq
    USBVirtualComDriver(虚拟串口驱动)……