C++中Polymorphism的实现

In programming languages, polymorphism means that some code or operations or objects behave differently in different contexts.
C++ polymorphism means that a call to a member function will cause a different function to be executed depending on the type of object that invokes the function.
A virtual function is a function in a base class that is declared using the keyword virtual. Defining in a base class a virtual function, with another version in a derived class, signals to the compiler that we don't want static linkage for this function. What we do want is the selection of the function to be called at any given point in the program to be based on the kind of object for which it is called. This sort of operation is referred to as dynamic linkage, or late binding.
Virtual Function is a function in base class, which is overrided in the derived class, and which tells the compiler to perform Late Binding on this function.
In Late Binding function call is resolved at run time. Hence, now compiler determines the type of object at runtime, and then binds the function call. Late Binding is also called Dynamic Binding or Runtime Binding.
Late binding is also known as Dynamic Binding or Runtime Binding. Sometimes compiler can’t know which function will be called till program is executed (runtime). This is known as late binding. Binding is the process which is used by the compiler to convert identifiers (such as variable and function names) into machine language addresses.
It is a mechanism in which the method called by an object gets associated by name in runtime. Late binding happens when virtual keyword is used in member function declaration.
C++ implementation of virtual functions uses a special form of late binding known as virtual table (VTable). When a class declares a virtual member function,most of the compilers add a hidden member variable that represents a pointer to Virtual Method Table (VMT or VTable). We will call this pointer as vptr. This table represents an array of pointers to virtual functions. At compile-time,there is no information about which function will be called. At runtime,pointers from Virtual Method Table will point to right functions.
Destructor is called when an object is destroyed. C++ provides a default destructor for all the classes. However, sometimes there is a need to create your own destructor. It can be done in the case you need to deallocate memory, free a resource etc. When you have a hierarchy of classes, it is strongly recommended to use virtual destructors.
A base class pointer can point to either an object of the base class or of any publicly-derived class.
Type ofpolymorphism:
(1)、Compile time polymorphism: In C++ programming you can achieve compile time polymorphism in two way, which is given below: Method overloading and Method overriding.
Method Overloading in C++: Whenever same method name is exiting multiple times in the same class with different number of parameter or different order of parameters or different types of parameters is known as method overloading.
Method Overriding in C++: Define any method in both base class and derived class with same name,same parameters or signature, this concept is known as method overriding.
(2)、Run time polymorphism: In C++ Run time polymorphism can be achieve by using virtual function. A virtual function is a member function of class that is declared within a base class and re-defined in derived class. When you want to use same function name in both the base and derived class, then the function in base class is declared as virtual by using the virtual keyword and again re-defined this function in derived class without using virtual keyword.
In C++, polymorphism usually refers to being able to access different types of objects through a common base class -- specifically using a pointer of the type of a base object to point to object(s) which derive from that base class.
多态性可以简单地概括为”一个接口,多种方法”。允许将子类类型的指针赋值给父类类型的指针。可以通过指向基类的指针,来调用实现派生类中的方法。程序在运行时才决定调用的函数。
在C++中,谈及多态时,默认就是指动态多态,而静态多态则是指基于模板的多态。
多态性分为两类:静态多态性和动态多态性。函数重载和运算符重载实现的多态性属于静态多态性,在程序编译时系统就能决定调用的是哪个函数,因此静态多态性又称编译时的多态性。静态多态性是通过函数的重载实现的(运算符重载实质上也是函数重载)。动态多态性是在程序运行过程中才动态地确定操作所针对的对象。它又称运行时的多态性。动态多态性是通过虚函数(virtual function)实现的。
封装可以使得代码模块化,继承可以扩展已存在的代码,他们的目的都是为了代码重用。而多态的目的则是为了接口重用。
虚函数的作用: 允许在派生类中重新定义与基类同名的函数,并且可以通过基类指针或引用来访问基类和派生类中的同名函数。
虚函数的使用注意事项:
(1)、如果虚函数在基类与派生类中出现,仅仅是名字相同,而形式参数不同,或者是返回类型不同,那么即使加上了virtual关键字,也是不会进行后绑定的。
(2)、只有类的成员函数才能声明为虚函数,因为虚函数仅适合用与有继承关系的类对象,所以普通函数不能声明为虚函数。
(3)、静态成员函数不能是虚函数,因为静态成员函数的特点是不受限制于某个对象。被static修饰的函数在编译时要求前绑定,而虚函数是后绑定,而且被两者修饰的函数声明周期也不一样。
(4)、内联函数不能是虚函数,因为内联函数不能在运行中动态确定位置。即使虚函数在类的内部定义,但是在编译的时候系统仍然将它看做是非内联的。内联函数每个对象一个拷贝,无映射关系。
(5)、构造函数不能是虚函数,因为在构造函数时,对象还是一片未定型的空间,对象还没有完成实例化,只有构造完成后,对象才是具体类的实例。
(6)、析构函数可以是虚函数,而且通常声明为虚函数,以防止可能造成的内存泄露。析构函数的作用是在对象撤销之前做必要的”清理现场”的工作。当派生类的对象从内存中撤销时一般先调用派生类的析构函数,然后再调用基类的析构函数。但是,如果用new运算符建立了临时对象,若基类中有析构函数,并且定义了一个指向该基类的指针变量。在程序用带指针参数的delete运算符撤销对象时,会发生一个情况:系统会只执行基类的析构函数,而不执行派生类的析构函数。当基类的析构函数为虚函数时,无论指针指的是同一类族中的哪一个类对象,当对象撤销时,系统会采用动态关联,调用相应的析构函数,对该对象进行清理工作。如果将基类的析构函数声明为虚函数,由该基类所派生的所有派生类的析构函数也都自动成为虚函数(即使派生类的析构函数与基类的析构函数名字不相同)。在程序中最好把基类的析构函数声明为虚函数。这将使所有派生类的析构函数自动成为虚函数。这样,如果程序中用delete运算符准备删除一个对象,而delete运算符的操作对象是指向派生类对象的基类指针,则系统会调用相应类的析构函数。
(7)、虚函数只能借助于指针或者引用来达到多态的效果。
(8)、派生类中定义的虚函数除必须与基类中的虚函数同名外,还必须同参数表,同返回类型,否则被认为是重载,而不是虚函数。
(9)、虚函数执行速度要稍慢一些。因为,为了实现多态性,每一个派生类中均要保存相应虚函数的入口地址表,函数的调用机制也是间接实现。
override是指派生类重写基类的虚函数,重写的函数必须有一致的参数表和返回值,称为”覆盖”或”重写”。overload为”重载”,是指编写一个与已有函数同名但是参数表不同的函数。
每一个有虚函数的类(或有虚函数的类的派生类)都有一个虚函数表,该类的任何对象都放着虚函数表的指针。虚函数表中列出了该类的虚函数地址。因此带有虚函数的类会比相应不带虚函数的类,大小多4个字节,这4个字节即是虚函数表的指针的大小。

下面是从其他文章中copy的测试代码,详细内容介绍可以参考对应的reference:

#include "polymorphism.hpp"
#include <iostream>
#include <string>

///
// reference: http://www.cplusplus.com/doc/tutorial/polymorphism/
class Polygon {
protected:
	int width, height;
public:
	void set_values(int a, int b)
	{
		width = a; height = b;
	}
};

class Rectangle : public Polygon {
public:
	int area()
	{
		return width * height;
	}
};

class Triangle : public Polygon {
public:
	int area()
	{
		return (width * height / 2);
	}
};

int test_polymorphism1()
{
	Rectangle rect;
	Triangle trgl;
	Polygon poly;
	Polygon* ppoly1 = ▭
	Polygon* ppoly2 = &trgl;

	ppoly1->set_values(4, 5);
	ppoly2->set_values(4, 5);

	std::cout << rect.area() << '\n';
	std::cout << trgl.area() << '\n';

	return 0;
}


// reference: http://www.tutorialspoint.com/cplusplus/cpp_polymorphism.htm
class Shape_2 {
protected:
	int width, height;
public:
	Shape_2(int a = 0, int b = 0)
	{
		width = a;
		height = b;
	}
	virtual int area()
	{
		std::cout << "Parent class area :" << std::endl;
		return 0;
	}
};

class Rectangle_2 : public Shape_2{
public:
	Rectangle_2(int a = 0, int b = 0) :Shape_2(a, b) { }
	int area()
	{
		std::cout << "Rectangle class area :" << std::endl;
		return (width * height);
	}
};

class Triangle_2 : public Shape_2{
public:
	Triangle_2(int a = 0, int b = 0) :Shape_2(a, b) { }
	int area()
	{
		std::cout << "Triangle class area :" << std::endl;
		return (width * height / 2);
	}
};

int test_polymorphism2()
{
	Shape_2 *shape;
	Rectangle_2 rec(10, 7);
	Triangle_2 tri(10, 5);

	// store the address of Rectangle
	shape = &rec;
	// call rectangle area.
	shape->area();

	// store the address of Triangle
	shape = &tri;
	// call triangle area.
	shape->area();

	return 0;
}

///
// reference: http://www.learncpp.com/cpp-tutorial/122-virtual-functions/
class Animal
{
protected:
	std::string m_strName;

	// We're making this constructor protected because
	// we don't want people creating Animal objects directly,
	// but we still want derived classes to be able to use it.
	Animal(std::string strName) : m_strName(strName) {}

public:
	std::string GetName() { return m_strName; }
	virtual const char* Speak() { return "???"; }
};

class Cat : public Animal
{
public:
	Cat(std::string strName) : Animal(strName) {}

	virtual const char* Speak() { return "Meow"; }
};

class Dog : public Animal
{
public:
	Dog(std::string strName) : Animal(strName) {}

	virtual const char* Speak() { return "Woof"; }
};

static void Report(Animal &rAnimal)
{
	std::cout << rAnimal.GetName() << " says " << rAnimal.Speak() << std::endl;
}

int test_polymorphism3()
{
	Cat cCat("Fred");
	Dog cDog("Garbo");

	Report(cCat); // Fred says Meow
	Report(cDog); // Garbo says Woof

	Cat cFred("Fred"), cTyson("Tyson"), cZeke("Zeke");
	Dog cGarbo("Garbo"), cPooky("Pooky"), cTruffle("Truffle");

	// Set up an array of pointers to animals, and set those pointers to our Cat and Dog objects
	Animal *apcAnimals[] = { &cFred, &cGarbo, &cPooky, &cTruffle, &cTyson, &cZeke };
	for (int iii = 0; iii < 6; iii++)
		std::cout << apcAnimals[iii]->GetName() << " says " << apcAnimals[iii]->Speak() << std::endl;

	return 0;
}

//
// reference: http://www.cprogramming.com/snippets/source-code/polymorphism-example
// abstract base class
class base
{
protected:  // attribute section
	int num1;
	int num2;
	int result;
public:  // behavior section
	void setVar(int n1, int n2)
	{
		num1 = n1;
		num2 = n2;
	}
	virtual void op() = 0;  // pure virtual function
	int getresult() { return result; }
};

class add : public base  // add class inherits from base class
{
public:
	void op() { result = num1 + num2; }
};

//sub class inherit base class
class sub : public base
{
public:
	void op() { result = num1 - num2; }
};

int test_polymorphism4()
{
	int x, y;
	base *m; //pointer variable declaration of type base class
	add ad;  //create object1 for addition process
	sub su;  //create object2 for subtraction process
	std::cout << "\nEnter two numbers seperated by space, or press Ctrl+z to Exit: ";

	while (std::cin >> x >> y) {
		m = &ad;
		m->setVar(x, y);
		m->op(); //addition process, even though call is on pointer to base!
		std::cout << "\nResult of summation = " << m->getresult();
		m = &su;
		m->setVar(x, y);
		m->op(); //subtraction process, even though call is on pointer to base!
		std::cout << "\nResult of subtraction = " << m->getresult() << std::endl << std::endl;
		std::cout << "\nEnter two numbers seperated by space or press Ctrl+z to Exit: ";
	}

	return 0;
}

GitHubhttps://github.com/fengbingchun/Messy_Test

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值