Hi friends

If we will override nonstatic methods or if we will overload non static methods means shall we say it is the run time polymorphism?

If i will override static method means, friends are saying it is not compile time polymorphism, It is method hiding.

I need some examples to demonstrate this to my friends.


Thnks in advance!

Recommended Answers

All 17 Replies

If i will get any demonstration by comparing polymorphism in c++ and java means that will be helpful for me.

Thanks in advance !

I can only give you an example in C++, because, to my knowledge, you cannot do compile-time polymorphism in Java. (and anyways, such a question belongs in the Java forum)

This is dynamic polymorphism in C++:

#include <iostream>

struct Animal {
  virtual void doCry() = 0;
};

struct Dog : Animal {
  void doCry() {
    std::cout << "Woof Woof!" << std::endl;
  };
};

struct Cat : Animal {
  void doCry() {
    std::cout << "Miaou.." << std::endl;
  };
};

void makeAnimalCry(Animal& a) {
  a.doCry(); // this call will be dispatched (at run-time) to the correct implementation.
};

int main() {
  Dog d;
  makeAnimalCry(d);
  Cat c;
  makeAnimalCry(c);
  return 0;
};

This is static polymorphism in C++:

#include <iostream>

struct Dog {
  void doCry() {
    std::cout << "Woof Woof!" << std::endl;
  };
};

struct Cat {
  void doCry() {
    std::cout << "Miaou.." << std::endl;
  };
};

// this function will be generated, at compile-time, for the given type of animal.
template <typename Animal>
void makeAnimalCry(Animal& a) {
  a.doCry(); //since this is generated at compile-time, no dispatch is needed, this is simple a normal function call (and possibly inlined as well, which is not possible in general in the dynamic case).
};

int main() {
  Dog d;
  makeAnimalCry(d);
  Cat c;
  makeAnimalCry(c);
  return 0;
};

Java is a language with JIT (Just-In-Time) compilation, so it is hard to distinguish compile-time mechanisms from run-time mechanisms, because it runs and compiles at the same time. And the JIT compiler can probably resolve some polymorphic function calls such that dynamic dispatch is not necessary (most C++ compilers do that as well). In that sense, dynamic polymorphism is sometimes reduced to static polymorphism in either languages, this is very common, but I don't think it's what you mean by compile-time polymorphism.

As you can see, static polymorphism in C++ is based on templates which generate code once they are given the required types to generate the code for, and thus, everything happens at compile-time, since, at the end, you just have a normal function or class. This means that you can write functions which work for any type that models some sort of "concept" (analogous to a base-class, but not formalized by code). So, you get a polymorphic behaviour (substitutability) which is realized at compile-time and entails no run-time overhead and opens many optimization opportunities (like inlining, return-value-optimization, etc.) which gives this technique unrivaled performance at run-time (but also long compilation times).

The Java feature that sort-of corresponds to templates in C++, is the so-called "generics". But this mechanism is very limited compared to C++'s templates, and I doubt you can achieve much with them. They are mostly designed for very basic use like making a container (or called "collection" in Java). They also have a number of problems that limit their capabilities and performance. Ask a Java programmer for examples of static polymorphism in Java using generics.


>>If i will override static method means, friends are saying it is not compile time polymorphism, It is method hiding.

Your friends are correct. "overriding" a static method is just dangerous. In Java, all non-static methods are "virtual" meaning that they can be overridden. But, remember that static methods are not virtual and cannot be overridden, they can simply be hidden. When you have a base class and a derived class with the same static method, code that refers to the derived class will call the "overridden" function while code that refers to the base class will call the base-class's static function. That doesn't give you any polymorphism, and it just confuses everyone because it is hard to tell in which situation which static function gets called. Just don't do that, period.

>>This is static polymorphism in C++:
I don't get why that's called static polymorphism? All that's doing is generating multiple function for each type. There is nothing polymorphic about it. Polymorpic is more like a 1->many relationships, while that's like 1->1 relationship, that is each type has its own function. What do you think?

Here is a compile time Polymorphism example for JAVA using the above classes.

EDIT: ITS SHOWING C++ CODE, BUT THESE ARE ACTUALLY JAVA CODE.

package com.generic.myanimal;

public interface GenericAnimal {
	
	public void makeAnimalCry();
}
package com.generic.myanimal;

public class Dog implements GenericAnimal {

	@Override
	public void makeAnimalCry() {
		// TODO Auto-generated method stub
		System.out.print("Woof Woof!!");
	}

}
package com.generic.myanimal;

public class Cat implements GenericAnimal {

	@Override
	public void makeAnimalCry() {
		// TODO Auto-generated method stub
		System.out.print("Miaou..");
	}

}
public class Animal <T extends GenericAnimal>{

	
	public void makeAnimalCry(T animal){
			animal.makeAnimalCry();
	}
	/**
	 * @param args
	 */
	public static void main(String[] args) {
		Dog dog = new Dog();
		Cat cat = new Cat();
		
		Animal<Dog> animal1 = new Animal<Dog>();
		animal1.makeAnimalCry(dog);
		
		Animal<Cat> animal2 = new Animal<Cat>();
		animal2.makeAnimalCry(cat);
		
	}

}

I am not expert of java, so cant give expert opinion, or I should say will give more biased opinion towards c++.

But polymorphism in C++ is way too powerful than Java. I am off to home now. Will try to write an example why C++ is more powerful.

Will try to write an example why C++ is more powerful.

Fine.

>>I don't get why that's called static polymorphism?

Static: A mechanism which occurs at compilation or linking time.

Polymorphism: A programming language feature that allows values of different data types to be handled using a uniform interface. The concept of parametric polymorphism applies to both data types and functions. A function that can evaluate to or be applied to values of different types is known as a polymorphic function.

The example I showed fits perfectly into that definition, and this is why it is called static polymorphism.

>>All that's doing is generating multiple function for each type. There is nothing polymorphic about it.

Yeah, so what. There are, obviously, many other things that can be done in generic programming as well. But anyways, what about dynamic polymorphism? All it does is look-up a function pointer in a table, "there is nothing polymorphic about it". Polymorphism is an abstract concept, the implementation details involved in realizing it don't matter. It's the design perspectives that matter.

>> Polymorphism is more like a 1->many relationships, while that's like 1->1 relationship, that is each type has its own function.

You are right and wrong. To the compiler, it is just one function for each type, but this is after the fact, because it is done at compile-time, so, once compiled, the code is not "polymorphic" in the (1 -> many) kind-of way. But, once compiled, the polymorphism has already been realized. If you take the case of dynamic polymorphism, which occurs at run-time, once the code has executed, there will be one execution path for each polymorphic object used. The only difference is that the creation of the individual execution paths is delayed until run-time in the case of dynamic polymorphism, while it is done during compilation in the case of static polymorphism. It is not because something occurs at compile-time that it doesn't occur. Open your mind, and see the compilation process as just another part of the program's execution.

Here's something for you to reflect on:

//Here is a simple function that checks if 'char' is smaller than 'int'.
void char_is_smaller_dyn() {
  if( sizeof(char) < sizeof(int) )
    std::cout << "char is smaller than int" << std::endl;
  else
    std::cout << "char is not smaller than int" << std::endl;
};

//Here is a meta-function that evaluates if 'char' is smaller than 'int':
template <bool B>
struct if_ {
  static void then_else_(const std::string&, const std::string& msg) {
    std::cout << msg << std::endl;
  };
};

template <>
struct if_<true> {
  static void then_else_(const std::string& msg, const std::string&) {
    std::cout << msg << std::endl;
  };
};

void char_is_smaller_sta() {
  if_< (sizeof(char) < sizeof(int)) >::then_else_(
    "char is smaller than int",
    "char is not smaller than int"
  );
};

Would you say that the first version is the only one that evaluates the condition? The second version does not evaluate any condition at run-time, but does that mean that it does not evaluate any condition?

You have to see that if things are done at compile-time, they're still done. If polymorphism is realized at compile-time, it is still realized.

>> What do you think?

I think you need to open your mind to other ways of thinking about execution and polymorphism.

I can only give you an example in C++, because, to my knowledge, you cannot do compile-time polymorphism in Java. (and anyways, such a question belongs in the Java forum)

This is dynamic polymorphism in C++:

#include <iostream>

struct Animal {
  virtual void doCry() = 0;
};

struct Dog : Animal {
  void doCry() {
    std::cout << "Woof Woof!" << std::endl;
  };
};

struct Cat : Animal {
  void doCry() {
    std::cout << "Miaou.." << std::endl;
  };
};

void makeAnimalCry(Animal& a) {
  a.doCry(); // this call will be dispatched (at run-time) to the correct implementation.
};

int main() {
  Dog d;
  makeAnimalCry(d);
  Cat c;
  makeAnimalCry(c);
  return 0;
};

This is static polymorphism in C++:

#include <iostream>

struct Dog {
  void doCry() {
    std::cout << "Woof Woof!" << std::endl;
  };
};

struct Cat {
  void doCry() {
    std::cout << "Miaou.." << std::endl;
  };
};

// this function will be generated, at compile-time, for the given type of animal.
template <typename Animal>
void makeAnimalCry(Animal& a) {
  a.doCry(); //since this is generated at compile-time, no dispatch is needed, this is simple a normal function call (and possibly inlined as well, which is not possible in general in the dynamic case).
};

int main() {
  Dog d;
  makeAnimalCry(d);
  Cat c;
  makeAnimalCry(c);
  return 0;
};

Java is a language with JIT (Just-In-Time) compilation, so it is hard to distinguish compile-time mechanisms from run-time mechanisms, because it runs and compiles at the same time. And the JIT compiler can probably resolve some polymorphic function calls such that dynamic dispatch is not necessary (most C++ compilers do that as well). In that sense, dynamic polymorphism is sometimes reduced to static polymorphism in either languages, this is very common, but I don't think it's what you mean by compile-time polymorphism.

As you can see, static polymorphism in C++ is based on templates which generate code once they are given the required types to generate the code for, and thus, everything happens at compile-time, since, at the end, you just have a normal function or class. This means that you can write functions which work for any type that models some sort of "concept" (analogous to a base-class, but not formalized by code). So, you get a polymorphic behaviour (substitutability) which is realized at compile-time and entails no run-time overhead and opens many optimization opportunities (like inlining, return-value-optimization, etc.) which gives this technique unrivaled performance at run-time (but also long compilation times).

The Java feature that sort-of corresponds to templates in C++, is the so-called "generics". But this mechanism is very limited compared to C++'s templates, and I doubt you can achieve much with them. They are mostly designed for very basic use like making a container (or called "collection" in Java). They also have a number of problems that limit their capabilities and performance. Ask a Java programmer for examples of static polymorphism in Java using generics.


>>If i will override static method means, friends are saying it is not compile time polymorphism, It is method hiding.

Your friends are correct. "overriding" a static method is just dangerous. In Java, all non-static methods are "virtual" meaning that they can be overridden. But, remember that static methods are not virtual and cannot be overridden, they can simply be hidden. When you have a base class and a derived class with the same static method, code that refers to the derived class will call the "overridden" function while code that refers to the base class will call the base-class's static function. That doesn't give you any polymorphism, and it just confuses everyone because it is hard to tell in which situation which static function gets called. Just don't do that, period.

I think there may be an error in your dynamic example.

Static: A mechanism which occurs at compilation or linking time.

Based on this, your dynamic example is more of a static example because all types, linking, and execution paths are determined at compile time. When I think of "dynamic" polymorphism I think of something more like this:

#include <iostream>
 
struct Animal {
  virtual void doCry() = 0;
};
 
struct Dog : Animal {
  void doCry() {
    std::cout << "Woof Woof!" << std::endl;
  };
};
 
struct Cat : Animal {
  void doCry() {
    std::cout << "Miaou.." << std::endl;
  };
};

void makeAnimalCry(Animal *a) {
  a->doCry(); // this call will be dispatched (at run-time) to the correct implementation.
};

int main() {
  char choice = '/0';
  Animal *theAnimal = NULL;
  std::cout << "What animal would you like to speak to:\nd -> Dog\nc -> Cat";
  std::cin >> choice;
  switch (choice) {
   case 'c':
    theAnimal = new Cat;
    break;
   case 'd':
    theAnimal = new Dog;
    break;
  }
  makeAnimalCry(theAnimal);
  delete theAnimal
  return 0;
}

In this example, the execution path is not pre-determined. It is not known what the execution path and associated types are or should be until the user interacts with the program at run-time. Of course, all of the relevant code already exists (because C++ doesn't do JIT in the same way as Java) but the links haven't been established because the compiler has no way of knowing how the user will interact with the program.

Or am I mis-interpreting something?

>>Or am I mis-interpreting something?

No, your logic is good, it is just that you seem to be tying the concept of "polymorphism" to a mechanism for run-time flexibility. Of course, my dynamic example was very trivial and didn't show the run-time flexibility that dynamic polymorphism gives you. Of course, the compiler optimization turns my dynamic polymorphism example into static polymorphism, but I was making a point about polymorphism implemented dynamically (virtual functions) or statically (templates) and how they both achieve polymorphism. But like you pointed out, they are different, of course, they are not equivalent but they are both forms of polymorphism. As you know, polymorphism is a means to achieve flexibility in a software by being able to substitute anything that implements a given abstraction (a base-class or a template-argument's concept) into an algorithm or method. The difference between static and dynamic polymorphism is that the static version only provides that flexibility (or substitutability) at compile-time, while the dynamic version allows you to get run-time flexibility. That's the difference, and that is what should be the motivation for using dynamic polymorphism instead of static. If you need run-time flexibility then use dynamic polymorphism, if not then use static polymorphism, because you shouldn't pay the price for run-time flexibility if you don't need it (the "price" of run-time flexibility is the slight virtual-dispatch overhead, but mainly the lack of opportunity of performance optimizations by the compiler such as inlining and elision of temporaries). In the tradition of C++, you pay for what to get, but you only have to pay for what you need.

This is why you will most commonly find static polymorphism used in library code that is meant to be used in the implementation of other things (like all the STL algorithms which use static polymorphism profusively). Because the implementation of these things are usually far from the user of the application and can thus be set at compile-time.

And this is why dynamic polymorphism is most commonly found in programming that is closer to the user of the application, like GUI programming and computer-game programming, because it needs the run-time flexibility to be able to react to the user input.

When I design software, I think about the task in terms of the methods I want to apply, the abstractions that these methods operate on, and the concrete cases (or implementations) on which I want to apply the method to. In OOP, abstractions correspond to base-classes (or interfaces) and concrete cases correspond to concrete derived classes. In Generic Programming, abstractions correspond to "concepts" and "traits" while concrete cases correspond to types that model those concepts and have those traits. The point I'm trying to get across is that the way you think and design the software is essentially the same. Only the need for run-time flexibility determines whether this design is realized statically or dynamically. The design itself relies on polymorphism (amongst other things) which is, as a design-feature, available to both realizations, static or dynamic.


>>(because C++ doesn't do JIT in the same way as Java)

C++ does not do JIT at all.

>>>>(because C++ doesn't do JIT in the same way as Java)

>>C++ does not do JIT at all.
I was actually referring to the tendency of some compilers to delay allocation of a variable until it's absolutely needed rather than doing it when the declaration is made.

>>I was actually referring to the tendency of some compilers to delay allocation of a variable until it's absolutely needed rather than doing it when the declaration is made.

That sounds very peculiar. Do you have any reference describing this? It would seem to me like a violation of the "as if" rule for allowed optimization (I thought the only allowed exception to the rule was elision of temporaries). I would be very interested in learning what that's about.

Unfortunately I don't. It was a very long time ago that I "heard" about that, here on DaniWeb if I remember correctly. I can see what I can find, but I doubt I'll have much luck.

>>>>(because C++ doesn't do JIT in the same way as Java)

>>C++ does not do JIT at all.
I was actually referring to the tendency of some compilers to delay allocation of a variable until it's absolutely needed rather than doing it when the declaration is made.

Are you referring to pointers, or in general all data-types?

I don't know. I'm starting to think I may have imagined something; I haven't been able to find the reference. I'm fairly sure it only applied to dynamically allocated "pointers".

The "new" doesn't execute until absolutely necessary. If your "new" statement is on Line 20, but you don't ever use the pointer until Line 100, the allocation won't actually occur until just before then. Obviously, this is a somewhat contrived example, but you get the idea.

The "new" doesn't execute until absolutely necessary.

That would be difficult to implement in any useful manner. Perhaps you're thinking of lazy initialized objects? That has the behavior you're talking about, but it's a part of the class implementation rather than the compiler.

I don't know. I'm starting to think I may have imagined something

I think the confusion comes from the overcommit feature of some OSes. Indeed, memory allocation routine may just reserve the address space, and postpone actual mapping until the first access. So an object with the trivial constructor may remain in the aetherial state for a while. However, new would execute exactly when it is called.

commented: that makes more sense. thanks +14

That would be difficult to implement in any useful manner. Perhaps you're thinking of lazy initialized objects? That has the behavior you're talking about, but it's a part of the class implementation rather than the compiler.

Thanks, Narue, "lazy ... objects" sounds familiar. I was starting to think I was losing my marbles.

Admittedly, I'm rather confused, but at least I'm not crazy. :)

Be a part of the DaniWeb community

We're a friendly, industry-focused community of developers, IT pros, digital marketers, and technology enthusiasts meeting, networking, learning, and sharing knowledge.