What will happen if we assign child handle to parent handle and the result in case of accessing parent handle? - system-verilog

Problem statement: there are 2 classes (parent and child class). Both have same display function in it. I have assigned child class handle to parent class handle by "p=c;" after that, I was trying to access p.display(), but in my understanding it should use function from child class. But, after run, I see it is printing from parent class. Any clue why?
class parent;
function void display();
$display("I am in parent");
endfunction
endclass
class child extends parent;
function void display();
$display("I am in child");
endfunction
endclass
module tb;
parent p;
child c;
initial begin
p = new();
c = new();
$display("1: %d %d", p , c);
p = c ;
$display("%d %d", p , c);
p.display();
end
endmodule

Your example is nearly identical to the example in IEEE Std 1800-2017, section 8.14 Overridden members. The behavior of your simulation is thoroughly described there:
To call the overridden method via a base class object (p in the
example), the method needs to be declared virtual.
To get p.display to I am in child, you should declare your display functions as virtual:
class parent;
virtual function void display();
$display("I am in parent");
endfunction
endclass
class child extends parent;
virtual function void display();
$display("I am in child");
endfunction
endclass

Parent and child are poor choices for describing class inheritance. When you construct an extended class, there is only one object which contains both the base and extended class properties.
When you use a base class variable to access properties in an extended class object, you can only access the properties known to the base class variable's type.
So when you use the p class variable, it will call parent::display() even though child::display exists, but it is hidden.
If you declare parent::display as a virtual method, only then will it look for the most extended override of that method.

Related

Converting UML to code c++. Problem with inheritence. Do constructors of all classes run when object of any one of them is created?

I have this UML diagram
Ad this is the corresponding C++ code
//Parent class Flight
class Flight
{
private:
int callNumber;
Airplane plane;
vector<Passenger> passengers;
public:
//Constructor
Flight();
//Functions
int getCallNum();
void setCallNum();
Airplane getPlane();
//What parameters are taken in these functions.
//I know they are of type Airplane and passenger but are they vectors?
void setPlane(Airplane);
void addPassenger(Passenger);
void removePassenger(Passenger);
};
//Airplane class, child of Flight
class Airplane : public Flight
{
private:
int firstClassSeats;
int economySeats;
public:
//Constructor
Airplane();
//Functions;
int getFirstClassSeats();
int getEconomySeats();
void setFirstClassSeats();
void setEconomySeats();
};
//Passenger class, child of FLight
class Passenger : public Flight
{
private:
string name;
int age;
string address;
public:
//Constructor
Passenger();
//Functions
string getName();
int getAge();
string getAddress();
void setName(string);
void setAge(int);
void setAddress(string);
};
I wonder:
do constructors of all classes run when an object of either parent or base class is created?
Can base class access functions or data of child classes?
I do not know how set plane function in parent class would look like. Would it take an object of type Airplane as an argument? Similarly, will addpassenger function in parent class take a vector of type Passenger as an argument?
In short
If A inherits B (or A specializes B), then you should be able to say A is a (kind of) B. When in doubt, prefer object composition over inheritance.
More details
The parameters taken by the member functions, are the parameters that you indicate for the operations in the diagram. No parameter in the diagram leads to no parameters in the code.
The inheritance here is ambigous. There is no inheritance in your diagram. There is some in your code, but it does not make so much sense: is a passenger really a flight? E.g. can a passenger fly, have a crew, etc.?
If the inheritance would be suitable, as a general rule in C++: the constructor of an object is always called when the object is created. In case of inheritance, all the constructors of the class hierarchy are invoked, starting with the base constructor, until the most derived constructor (the rules can be more tricky, for example in case of multiple inheritance). In UML, the rules on constructors are not fully specified as far as I know.
By default, a class can only access public members of another class. If a class is derived from a base class (in UML: if a class is a specialisation of a more general class), the derived class has only access to the public and protected members of the base class. Try to avoid protected, since it's a frequent cause of nasty bugs.
WHen implementing in C++ an UML class diagram, there is a tricky issue about the types of the properties and arguments, because C++ has a value semantic: if you pass an Airplane as argument, the original airplane object is copied. Same if you have an Airplane property. However, in UML, properties and associations have a reference semantic (except for datatypes), meaning that the airplane argument would still refer to the same original airplane. So in your specific case, you'd probably want to pass a reference or a (smart) pointer to an Airplane.

Initialize and modify class variables in derived classes

I want to initialize a variable class for my Base class and modify it only in some children classes.
The initialization of this class variable is in the header:
class Base{
public:
Base();
int a = 1;
The header of my derived class is:
class ChildA : public Base{
public:
ChildA ();
int a = 2;
}
Problem
I tried to run this:
Base classe*;
classe = new ChildA();
std::cout << classe->a << std::endl;
The problem is that, instead of printing 2 as I expected, it prints 1 (value initialized in my parent class). For other derived classes, I want classe->a to still return 1.
How can I solve this?
What you are seeing are the results of upcasting - having a base class point to a derived class object.
I highly recommend you read more on the topic, but a simplified picture is that the base class "carries" the whole object (base and derived content), but can access only it's original, own content. This is why you see a value from the base class rather than the derived class.
Lippman's C++ Primer has a very comprehensive explanation of upcasting, downcasting, object slicing, and other inheritance-related concepts. This includes implementing virtual functions which give you the functionality to invoke derived class functions through an interface that's common with base.
|----------------|-----------------|
| a (for Base) | a (for ChildA) |
|----------------|-----------------|
\________________/
^
|_ classe
Sorry if my drawing is not that good! As you can see in the above picture, when you create an object of type ChildA, this object contains a part for keeping the data members of the base class (i.e. Base) and another part for the data members of derived class (i.e. ChildA). Considering the fact that you have a pointer to the base class (i.e. classe), this pointer only allows you to access the base member variables and methods. So calling classe->a, returns the Base::a for you, that is 1.
If you change the type of classe pointer into ChildA, in that case calling classe->a will return 2, because it refers to the a inside the derived class, i.e. ChildA::a.
For other derived classes, I want classe->a to still return 1. How can
I solve this?
If you need in some derived classes to access different as, it is better to have a virtual function in the base class and override the base function if needed:
class Base {
public:
Base() {}
virtual int getA() { return a; }
private:
int a = 1;
};
class ChildA : public Base
{
public:
ChildA() {}
int a = 2;
};
class ChildB : public Base
{
public:
ChildB() {}
int getA() { return a; }
private:
int a = 2;
};
Now by calling getA() on a pointer of Base or ChildA, you will have 1, but calling getA on an object of type ChildB will return 2.

Factory overriding parameterized class in UVM

I have a parameterized seq_item as below
class seq_item#(int A = 64) extends uvm_sequence_item;
`uvm_object_param_utils(seq_item#(A))
rand logic [A-1:0] v;
constraint v_c {
v inside {[0:1000]};
}
endclass : seq_item
class extended_seq_item#(int A = 64) extends seq_item#(A);
`uvm_object_param_utils(extended_seq_item#(A))
constraint extended_v_c {
v inside {[10:50]};
}
endclass : extended_seq_item
class reg_adapter#(int A = 100) extends uvm_reg_adapter;
`uvm_object_param_utils(reg_adapter#(A))
typedef seq_item#(A) seq_item_t;
function new(string name = "reg_adapter")
seq_item_t req;
req = seq_item_t::type_id::create("req");
endfunction
endclass : reg_adapter
class test extends uvm_test;
`uvm_component_utils(test)
reg_adapter#(10) adapter;
function void build_phase(uvm_phase phase);
seq_item#(10)::type_id::set_type_override(extended_seq_item#(10)::get_type());
super.build_phase(phase);
adapter = reg_adapter::type_id::create("adapter");
endfunction : build_phase
endclass : test
In my UVM TB, I need to factory override all seq_item instances with extended_seq_item. Different instances will have different parameter values of A. How do I factory override this?
The problem is seq_item is from common collateral which has generic constraint for rand variable v which holds good for all IPs. For my IP, I need to add an additional constraint for v as given in extended_seq_item. My IP nuses reg_adapter which is expected to take extended_seq_item with additional constraints added
Thanks & Regards,
Kiran
Unfortunately, parameterized classes with different parameter values (specializations is the LRM's terminology) are treated as separate class types, so you'll need to provide an override for each parameter value.
seq_item#(10)::type_id::set_type_override(extended_seq_item#(10)::get_type());
seq_item#(20)::type_id::set_type_override(extended_seq_item#(20)::get_type());
seq_item#(30)::type_id::set_type_override(extended_seq_item#(30)::get_type());
If you can get this code into a place where A is already parametrized, like in a the build_phase of a parameterized env or agent, then it might not be as painful as the above.
Now that I see more code, the problem is the class scope in this line, which should have been caught as an error
adapter = reg_adapter::type_id::create("adapter");
should be written as
adapter = reg_adapter#(10)::type_id::create("adapter");

How to Dump a UVM TB class diagram?

Is it possible to dump a UVM(or SV) TB class/object hierarchy diagram?
It can help with easy code browsing and looking at the TB in general.
Thanks in advance :)
Questa has this capability as an add on. https://verificationacademy.com/verification-horizons/june-2014-volume-10-issue-2/Visualizer-Debug-Environment-Class-based-Testbench-Debugging-using-a-New-School-Debugger-Debug-This
I am not sure if it is possible to dump it into waveform dynamically (this may need simulator support). But if you just want to print the whole UVM verification environment that you created, then call uvm_top.print_topology() at the end_of_elaboration_phase.
class your_test extends uvm_test;
//...
virtual function void end_of_elaboration_phase(uvm_phase phase);
uvm_top.print_topology();
endfunction
endclass
If you are looking to print the entire topology, create a uvm_table_printer in your base test, and then use it in your end_of_elaboration_phase to print your class heirarchy in table format
class my_test extends uvm_test
uvm_table_printer m_printer;
// .... All other class variables
virtual function void build_phase(uvm_phase phase);
super.build_phase(phase);
m_printer = new();
// Rest of your build phase
endfunction
virtual function void end_of_elaboration_phase(uvm_phase phase);
`uvm_info(get_full_name(), "Printing test topology", UVM_NONE)
uvm_top.print_topology(m_printer);
endfunction
endclass;
This will print your entire class heirarchy in a readable table format. Note that it doesn't print out connections between ports though

custom report_server not working

The below code is not working
class my_report_server extends uvm_default_report_server;
`uvm_object_utils(my_report_server)
function new(string name="my_report_server");
super.new();
$display( "Constructing report serevr %0s",name);
endfunction : new
virtual function string compose_message( uvm_severity severity,string name,string id,string message,string filename,int line );
//implemeted own code.
endfunction
endclass
In the build_phase of test_base.
function void build_phase(uvm_phase phase)
my_report_server srv_h = new();
uvm_report_server::set_server(srv_h);
endfunction
I tried the same code and it prints messages from overridden class. There is no uvm_default_report_server class. Rather than it is simply uvm_report_server.
The following is my code snippet, which prints output as required:
// User report server
class my_report_server extends uvm_report_server;
`uvm_object_utils(my_report_server)
function new(string name="my_report_server");
super.new();
$display( "Constructing report serevr %0s",name);
endfunction : new
// Return type is string
virtual function string compose_message( uvm_severity severity,string name,string id,string message,string filename,int line );
// DEBUG MESSAGE
$display("From Super: \n %0s",super.compose_message(severity,name,id,message,filename,line));
//This display comes.
$display("This is from extended class");
endfunction
class test extends uvm_test;
// ... Some stuff here...
// Declare handle here.
my_report_server srv_h;
function void build_phase(uvm_phase phase);
super.build_phase(phase);
srv_h = new();
uvm_report_server::set_server(srv_h);
endfunction
endclass
One thing I would like to point out is you have declared handle inside build_phase itself. This might create scoping issues (though it works fine with VCS).
Also, note that the return type of compose_message function is string. So, there must be some output coming from your overridden function. I have added a debug message for the same, this prints the default formatted message.
More information on uvm_report_server can be found out at this class reference link.