CSC/ECE 517 Fall 2011/ch1 1i cl

From Expertiza_Wiki
Revision as of 01:11, 26 September 2011 by Yxue4 (talk | contribs) (→‎Virtual method)
(diff) ← Older revision | Latest revision (diff) | Newer revision → (diff)
Jump to navigation Jump to search

Introduction

In O-o languages Object-oriented languages, method is a subroutine that associates with the the class and defines the behaviors performed by the instances of the class. A ancestor class may has its descendant classes which inherit all its methods' propertiess(name,return type,etc). Method reimplementation is required when the decendent class needs to change the behavior of a method which was already implemented by the ancestor class, and it is more efficient to do so other than writing a new method. In different O-o languages, the ways to require or allow a class to reimplement methods are very different. So it is important for us to know how different languages handle the reimplementation and what are the advantages and disadvantages of them.

Reimplementation in different O-o languages

C++

General

There are two ways that C++ can re-implement methods in descendant classes, one is Overridden method, which is very similar with Java in overriding and overloading. The other is to re-implement methods by virtual function. Although the characteristic of virtual function can also be found in other languages such as Java, but in C++, virtual function is an important way to achieve polymorphism in C++.

Overridden


Quite similar to Java, the overridden in C++ has features as follows:

1, the functions should be in different classes, class A and subclass of A.

2, the name of functions should be the same.

3, the parameters of functions should be the same.

4, keyword” virtual” should be appeared in base class.

An example is explained as follows:

class Dog {
public:
	Dog(char* nm, int s):name(name),size(s){}
	virtual void print() const;
private:
	char* name;
	int size;
};

void Dog::print() const{  // print() method of base class
	std::cout<<”Name = ” << this->name << “; Size = ” << this->size;
}

class Dog_large: public Dog {
public:
	Dog_large(char * nm, int s, int t) : Dog(nm,s), type(t) {}
	virtual void print() const;

private:
	int type;
};

void Dog_large::print() const{
	Dog::print();
	Std::cout<<”; Type = ” << this-> type;
}

The main method will call the print method in class Dog and class Dog_car separately.

Int main(int argc, char** argv) {
	Dog dog_test(“Bart”, 11);
        Dog_test.print();
        //outputs:
        //Name = Bart; Size = 11

        Dog_large dog_large_test(“Lufu”,”17”,”11”);
        //the pointer to the most overridden method in the vtable in on Dog_car::print
        dog_large_test.print();// but this call does not illustrate overriding
        static_cast<Dog&>(dog_large_test).print(); // this one does
        //output
        // Name = Bart; Size = 17;Type = 11
}

Virtual method


To define a virtual method in C++, the virtual keyword should be added before the declaration of the method. This method’s behavior can be changed or we say overridden within an inheriting class by a function with the same signature. Although virtual method also exists in other programming language, this is an important way to achieve polymorphism in C++.


#include <iostream>
#include <vector>

class Material {
    public:
        virtual void dig() const { 
            std::cout << "It's dirty, I can't tell..." << std::endl; 
        }
        virtual ~Material() { 
        }
};
 
class Silver : public Material {
    public:
        void dig() const { 
            std::cout << "Found a silver, lucky!" << std::endl; 
        }
        virtual ~Silver() { 
        }
};
 
class Gold : public Material {
    public:
        void dig() const { 
            std::cout << "Found a gold, I'm rich!" << std::endl; 
        }
        virtual ~Gold() { 
        }
};
 
class GoldStatue : public Gold {
    public:
        void dig() const { 
            std::cout << "It is cursed!" << std::endl; 
        }
        virtual ~GoldStatue() { 
        }
};
 
class OtherMaterial : public Material {
        virtual ~OtherMaterial() { 
        }
};
 
int main() {
    std::vector<Material*> mat;
    mat.push_back(new Material());
    mat.push_back(new Silver());
    mat.push_back(new Gold());
    mat.push_back(new GoldStatue());
    mat.push_back(new OtherMaterial());
 
    for (std::vector<Material*>::const_iterator it = mat.begin(); it != mat.end(); ++it) {
        (*it)->dig();
        delete *it;
    }
 
    return 0;
}

Output with the virtual function Template:Cpp:

It's dirty, I can't tell...
Found a silver, lucky!
Found a gold, I'm rich!
It's cursed!
It's dirty, I can't tell...

Output, if Template:Cpp were not declared as virtual:

It's dirty, I can't tell...
It's dirty, I can't tell...
It's dirty, I can't tell...
It's dirty, I can't tell...
It's dirty, I can't tell...


What's different of "virtual" in C++


In C++, almost everything that has relevant to polymorphism is done by keyword “virtual”. In addition to this, virtual has other two functions.

Virtual base class

In base class A there are two subclass, B and C. D is inherited from B and C, but in D, there are two “A” as duplicate. Virtual base class is introduced to solve this problem. Shown as the example:

class B :virtual public A class C :virtual public A class D: public B, public C

Abstract class

Any class include: pure virtual function is called abstract class. Pure virtual function means no functionality in a function, and with a mark ‘=0’, as examples below:

void virtual foo() = 0;

The Virtual in C#


keyword” virtual ” can invoked virtual methods in both C++ and C#, these methods can be overridden in subclasses. However, it is in C# that the keyword “abstract” be introduced, to invoke virtual method without function. In C++, this job can be done by keyword” virtual”, we can it “pure virtual method”, class included pure virtual method can be called as “abstract class”.

In C#, Keyword “Virtual” can be added to “properties” and “methods” to indicate that the method in subclass can be rewrite. In general, keyword virtual in C# has been considerably impaired. In C#, the job in relevant of polymorphism has been taken by keyword” interface ” and “ abstract”, which was previously done by “virtual” in C++.

Java

General

In Java, we can use variaty of approaches to do the reimplementation. We still have approaches like Overridden Methods and Virtual Methods the same as what we have in C++, while there are some other convinient approaches such as Abstract Methods and Overloading Methods which C++ doesn't support. And we can put @override tag on top of a overriding mothed to have the complier check if the method is succesfully overridden.

Overriding

If a sub class inherited a method from the super class, as long as the method is not marked as final, the sub class can do overriding to reimplement the method and change the functionality of that method. But the overriding method must follow the requirement of the super class's method.

Here is an example.

class human{

   public void move(){
      System.out.println("Human can only walk");
   }
}

class superman extends human{

   public void move(){
      System.out.println("Superman can fly!");
   }
}

public class Test{

   public static void main(String args[]){
      human Li = new human();
      human Xue = new superman(); 

      Li.move();
      Xue.move();
   }
}

And the output result should be

Human can only walk
Superman can fly!

When you create Xue as an instance of superman class, its method move() will automatically override the its super class human's method with the same name.

In above example, Xue is defined as a type of human but it still can fly, that is because in compile time, it only checks the reference type, while in runtime, JVM knows the type of the object and will run the correct method which belongs to it.

Virtual Methods

In Java, all the method that are not marked as final are default virtual methods. So although we do have the idea of virtual methods in Java, actually it goes nothing different with the override methods.

Overloading

In Java, methods with the same name are allowed as long as they take different parameters. It is very convenient to have such kind of function because sometimes our method needs to take different types of parameters, and we don't want to have a list of different method names to confuse the users.

For example, while we have this method in the ancestor class

public int min(int n1, int n2) {
   int m;
   if (n1 < n2)
      m = n1;
   else
      m = n2;

   return m; 
}

We can still have this method in the descendant class

public int min(double n1, double n2){
   int m;
   if (n1 < n2)
      m = n1;
   else
      m = n2;

   return m; 
}

The program will invoke the right method depending on the type of the input.

But one important thing to remember is, only methods with different list of parameters are allowed to have the same names. We can not have overloaded methods based on different return types or modifiers. Different

Abstract Methods

In Java, when you want to define the structure of a class, and leave the implementation to its child classes, you can use a abstract class. In the abstract class, all the methods are abstract methods. They only have method signatures, but no method bodies. The child class can implement the abstract class and all the methods it has.

There are two important notes: 1. Once a method is declared as abstract method, its class must be declared as a abstract class. 2. The child classed must either override the methods or declare them as abstract themselves.

Here is the example, we defined a abstract class Shape

abstract class Draw {

	public String color;
	public Draw() {
	}
	public void setColor(String c) {
		color = c;
	}
	public String getColor() {
		return color;
	}
	abstract public double area();
}

Then we can define a sub class Point which extends Draw

public class Point extends Draw {

	static int x, y;
	public Point() {
		x = 0;
		y = 0;
	}
	public double area() {
		return 0;
	}
	public double perimeter() {
		return 0;
	}
	public static void print() {
		System.out.println("point: " + x + "," + y);
	}
	public static void main(String args[]) {
		Point p = new Point();
		p.print();
	}
}

When the sub class implements the super class, it must implement all of the methods that the super class has. It is not allowed to leave any abstract method not implemented, and once there is a abstract method in the sub class, it makes the sub class itself a abstract class.

Ruby

General

Methods are the cornerstone of object-oriented programming, and since Ruby is a pure-OO language (everything is an object), methods are inherent to the nature of Ruby. Object is the parent class of all classes in Ruby. Its methods are therefore available to all objects unless explicitly overridden. Method can be reimplementation in Ruby via Module and Random Parameter

Module


To better understand module in the reimplementation in sub-class of Ruby, first an example is given as follows:

module Gw
	def bye
		puts "Goodbye World"
	end
end

class Parent
	include Gw
end

class Child<Parent
end

obj=Child.new
obj.bye

It is very clear that Gw is a module include method 'bye'. 'Parent' is a class of module Gw, 'Child' inherited from 'Parent'. When method bye is invoked, Ruby will search this method in class 'Child', if nothing is found, Ruby will continue search in parent-class 'Parent', if the method is found, run it, if still not, continue this search from Object class and Kernel, until something is found or getting an error.

The introduction of module is to add flexibility to Ruby, make reimplementation possible. Since every class in Ruby inherited and only inherited from one class, which is different from multi-inherited of C++, it reduced the complexity and eliminated the risk of getting conflicts when inheriting from two different parent-classes that inherited from the same grandparent-class. And we still can achieve multi-inherit by mixin mechanism.

Random Parameter



Method with parameters in sub-class can be modified by random parameter by adding a * in ahead of parameters. An example is given below:

def max(first, *rest)
	max=first
	rest.each{|x|max=x if x>max}
	max
end

We can call this method, we got the output of

data = [3,2,1] m=max(*data)

output:

first =3, rest=[2,1] =>3


But if

m=max(data)

Output:

first= [3,2,1], rest=[] =>[3,2,1]

Advantage & Disadvantage

C++

The two ways of reimplantation can be achieve by keyword "virtual" , which also serve as a very useful and powerful tool in many other aspects, such as Virtual base class, and Abstract class, especially in polymorphism of C++.And multiple inheritance can be done with C++, which makes C++ very flexible in reimplementation. But Some times the variety use of keyword "virtual" may lead to confusion and misunderstanding.

Java

The abstract class and methods are very useful when you want to organize inheritance, it works as kind of template of the child classes which makes the inheritance very clear and easy to accomplish. And the overloading is also very helpful when you want to have a method that reads variety of parameters. The disadvantage is that the abstract class can not be instantiated, but it is not a problem for most of the cases. And also for overloading, developer needs to be very careful when you have have a method reads all sort of parameters to avoid confusion and mistakes. Also Java does not support multiple inheritance, and the implementation is not very flexible compare to C++.

Ruby

Compare to the static typed O-o language as C++ and Java, Ruby as a dynamic typed language can change the signature and properties of inherited methods in runtime. And all the methods in Ruby are default virtual which makes the override much easier and make the code more concise and readable. But the disadvantage is that the dynamic type increased the insecurity and instability of the program. Because sometimes you don't even know a object with wrong type is used until you see the error output, and it also increased the difficulty to debug.

Conclusion

Although there are pros and cons for each of the languages mentioned above, but actually all of them have great performance in method and class inheritance. Besides most of the disadvantages are avoidable when programming with care and using the appropriate approaches. So all of them are good choices to programmers and people can make their choice based on the different advantages they have.

Reference

"Tutorials Point.com" http://www.tutorialspoint.com/java/index.htm

"Java Beginner.com" http://www.javabeginner.com/learn-java/java-abstract-class-and-interface

http://en.wikipedia.org/wiki/Virtual_function

http://www.vckbase.com/document/viewdoc/?id=950

http://en.wikipedia.org/wiki/C%2B%2B

http://www.cnblogs.com/realyan/archive/2011/07/13/2105801.html

http://helloxuweifu.iteye.com/blog/1165745

http://qa.taobao.com/?p=11648

http://en.wikipedia.org/wiki/Inheritance_(object-oriented_programming)

http://en.wikipedia.org/wiki/Compile_time

http://en.wikipedia.org/wiki/Run_time_(program_lifecycle_phase)

http://en.wikipedia.org/wiki/Method_signature

http://en.wikipedia.org/wiki/Ruby

http://en.wikipedia.org/wiki/Modular_programming

http://en.wikipedia.org/wiki/Mixin

http://en.wikipedia.org/wiki/Return_type

See also

The JavaTM Tutorials http://download.oracle.com/javase/tutorial/index.html