`
banxi1988
  • 浏览: 153885 次
  • 性别: Icon_minigender_1
  • 来自: 桂林
社区版块
存档分类
最新评论

C++的静态绑定和动态绑定(或称静态联编和动态联编)

    博客分类:
  • C++
阅读更多
先看两个相似的程序的执行过程及结果:
首先是main()方法驱动Cpp文件如下:
#include "Test_StaticBinding_DynamicBinding.h"

int main() {

	Figure figure;
	cout<<"Figure的面积是: "<<figure.area()<<endl;

	Circle circle(2.0);
	cout<<"Circle的面积是: "<<circle.area()<<endl;

	Rectangle rect(3.0,4.0);
	cout<<"Rectangle的面积是: "<<rect.area()<<endl;

	return 0;
}
/**
 * 输出结果:
 *
 *1.使用静态绑定输出结果:
Figure的面积是: 0
Circle的面积是: 12.56
Rectangle的面积是: 12

 */


上面的代码是静态绑定的.当我们对于上面的代码进行改进时,
因为上面的Figure和Circle以及Rectangle类都有area()方法.并都输出结果.
输出代码大同小异.我们尝试把将其提取作为一个方法出来.即可以达到重构的效果.
重构后在Figure等类所在的头文件中添加如下非类方法:
void printArea(Figure &figure){
	cout<<"面积是: "<<figure.area()<<endl;
}

重构之后的main函数如下:
#include "Test_StaticBinding_DynamicBinding.h"

int main() {

	Figure figure;
	printArea(figure);

	Circle circle(2.0);
	printArea(circle);

	Rectangle rect(3.0,4.0);
	printArea(rect);

	return 0;
}
/**
 * 输出结果:
 2. 使用printArea()函数输出如下:
面积是: 0
面积是: 0
面积是: 0
 */


上面的程序在编译,运行时均没有出错,可是结果不对.
解析就是,编译器的编译时 将函数:
void printArea(Figure &figure);
中的形参firgure所执行的操作静态绑定到Figure类的area()方法上.这样访问的只是从基类中的area()方法.而不是所传递过来实例所在直接类的area()方法.所以输出结果不正确.

解决这个问题办法就是多态,或者是动态绑定,这个动态绑定是在运行时发生的.因此又被称为
运行时多态.
在C++中实现动态绑定要求成员函数用virtual来标记.
此时类的头文件如下:
#ifndef TEST_STATICBINDING_DYNAMICBINDING_H_
#define TEST_STATICBINDING_DYNAMICBINDING_H_
#include"common.h"
const double PI = 3.14;
class Figure{
public:
	Figure(){

	}
	virtual double area()const{
		return 0.0;
	}
};
class Circle:public Figure{
public:
	Circle(double radius){
		_radius = radius;
	}
	virtual double area()const{
		return PI*_radius*_radius;
	}
protected:
	double _radius;
};

class Rectangle:public Figure{
public:
	Rectangle(double length,double width){
		_length = length;
		_width = width;
	}
	virtual double area()const{
		return _length*_width;
	}
private:
	double _length;
	double _width;
};

void printArea(Figure &figure){
	cout<<"面积是: "<<figure.area()<<endl;
}
#endif /* TEST_STATICBINDING_DYNAMICBINDING_H_ */


输出结果如下:
/***
3.使用动态绑定加printArea()方法输出结果如下:
面积是: 0
面积是: 12.56
面积是: 12
**/


上面的重构还有一个问题就是,我们在打印面积时,没有指明是那一个形状(figure)的面积.
为了解决这个问题.我们为每一种形状添加一个属性.即形状名.
当为形状类添加name属性时,
出错一个报错如下:
引用

invalid in-class initialization of static data member of non-integral type ‘std::string’

在下面这个地址有关于这个问题更多的讨论.
http://stackoverflow.com/questions/1563897/c-static-constant-string-class-member

在我的教材中对于静态成员初始化是这样讲的:
引用

必须对静态成员初始化,只有这样编译程序才会为静态数据成员分配一个具体的空间.
静态数据成员不能在类中初始化.必须在类外部初始化,初始化语法如下:
<数据类型><类名>::<静态数据成员名>=<初始值>;


修改之后形状类的头文件如下:
#ifndef TEST_STATICBINDING_DYNAMICBINDING_H_
#define TEST_STATICBINDING_DYNAMICBINDING_H_
#include"common.h"

const double PI = 3.14;
class Figure{
public:
	static string name;
	Figure(){

	}
	virtual double area()const{
		return 0.0;
	}
};
string Figure::name = "Figure";

class Circle:public Figure{
public:
	static string name;
	Circle(double radius){
		_radius = radius;
	}
	virtual double area()const{
		return PI*_radius*_radius;
	}
protected:
	double _radius;
};
string Circle::name = "Circle";

class Rectangle:public Figure{
public:
	static string name;
	Rectangle(double length,double width){
		_length = length;
		_width = width;
	}
	virtual double area()const{
		return _length*_width;
	}
private:
	double _length;
	double _width;
};
string Rectangle::name = "Rectangle";

void printArea(Figure &figure){
	cout<<figure.name<<"面积是: "<<figure.area()<<endl;
}
#endif /* TEST_STATICBINDING_DYNAMICBINDING_H_ */


输出结果如下:
/**
Figure面积是: 0
Figure面积是: 12.56
Figure面积是: 12
**/


这个也就是说figure中的name属性也是静态绑定的.如何让静态属性动态绑定呢?
我尝试着在静态属性的声明当中添加一个virtual关键字.但是编译的时候报错了.
报错如下:
引用
member ‘name’ cannot be declared both virtual and static

百度Google了下没有找到解决方案:

不过在这个地址有人问了类似的问题.
地址如下:
http://stackoverflow.com/questions/7227236/can-we-have-a-virtual-static-method-c
解释如下:
引用

No. static means it doesn't need an object to operate on. virtual means the implementation depends on the type of the calling object. For static there is no calling object, so it doesn't make sense to have both static and virtual on the same function .

嗯,说得很有道理.

于是我想着给这个一个属性一个getter然后将getter设置成动态绑定的对吧.
还是有一个错误.我错了,我其实就算用getter这个getter也是一个静态方法啊.
用eclipse生成的getter方法如下:
	static string _name;
    static string getName() const;

我试图在声明这个属性时初始化它但是失败了.
报错如下:
引用
ISO C++ forbids initialization of member ‘_name’

哎C++的限制还真多啊?
好吧.我在构造函数中初始化吧.
然后我遇到一个调用同类中无参构造函数的问题如下:
	Rectangle(){
		_name = "Rectangle";
	}
	Rectangle(double length,double width){
		this();//error
		_length = length;
		_width = width;
	}

上面的this()调用是错的.
那如何在C++中调用同类中的无参构造函数呢?
用全名吗?或者还有其它方法?
我只能尝试自己调用了.如下:
	Rectangle(double length,double width){
		Rectangle();//		new (this)Rectangel();
		_length = length;
		_width = width;
	}

编译可以通过.
然后将name的getter设置为virtual的.但是运行结果出人意料之外如下:
Figure面积是: 0
面积是: 12.56
面积是: 12

后面的两个调用了自己的无参构造函数的name属性都没有得到初始化.
难道是因为调用了自己的无参构造函数其实是初始化了另一个对象?Rectange()
生成的对象又到了哪里去了呢? 或者是动态绑定不成功?
然后我在实际调用的有参构造函数中尝试一下.
果然不是动太绑定不成功而是Rectangle()生成的另外的类实例.找不到了.
// Rectangle构造方法改写如下.
	Rectangle(){

	}
	Rectangle(double length,double width){
		Rectangle();//		new (this)Rectangel();
		_name = "Rectangle";
		_length = length;
		_width = width;
	}
/** 结果:
Figure面积是: 0
面积是: 12.56
Rectangle面积是: 12
 **/

现在我们再来尝试下,我前面在网上查找到的一种调用方法.
看下通过new (this)Rectange()方法能成不?
看起来好像能成,因为有了一个(this)来调用了.
确实成了.
测试结果如下:
//修改之后的Circle构造函数:
	Circle(){
		_name = "Circle";
	}
	Circle(double radius){
		new (this)Circle();
		_radius = radius;
	}
/**
运行结果:
Figure面积是: 0
Circle面积是: 12.56
Rectangle面积是: 12
**/


此时类文件如下:
#ifndef TEST_STATICBINDING_DYNAMICBINDING_H_
#define TEST_STATICBINDING_DYNAMICBINDING_H_
#include"common.h"

const double PI = 3.14;
class Figure{
public:
	Figure(){
		_name = "Figure";
	}
    virtual string getName() const{
    	return _name;
    }

	virtual double area()const{
		return 0.0;
	}
private:
	string _name;

};

class Circle:public Figure{
public:
	Circle(){
		_name = "Circle";
	}
	Circle(double radius){
		new (this)Circle();
		_radius = radius;
	}
    virtual string getName() const{
    	return _name;
    }

	virtual double area()const{
		return PI*_radius*_radius;
	}


protected:
	double _radius;
private:
	string _name;

};

class Rectangle:public Figure{
public:
	Rectangle(){

	}
	Rectangle(double length,double width){
		Rectangle();//		new (this)Rectangel();
		_name = "Rectangle";
		_length = length;
		_width = width;
	}

   virtual string getName() const{
    	return _name;
    }

	virtual double area()const{
		return _length*_width;
	}

private:
	double _length;
	double _width;
	string _name;
};

void printArea(Figure &figure){
	cout<<figure.getName()<<"面积是: "<<figure.area()<<endl;
}

#endif /* TEST_STATICBINDING_DYNAMICBINDING_H_ */


总结:C++和Java还是区别挺多的.关于静态绑定,和动态绑定中C++与Java方面的比较见我的下一篇文章.
分享到:
评论

相关推荐

    深入理解C++的动态绑定和静态绑定

    在C++编程语言中,动态绑定和静态绑定是两种关键的多态实现方式,它们对于理解和编写高效、灵活的代码至关重要。多态性允许我们通过一个共同的基类接口访问不同派生类的对象,从而提高了代码的重用性和可扩展性。 ...

    (转)C++中解析动态联编

    动态联编是C++中实现多态性的重要技术,它允许在运行时根据对象的实际类型来决定调用哪个函数。...动态联编的使用极大地增强了C++的灵活性和代码复用性,是C++成为一种强大而复杂的编程语言的关键要素之一。

    深入理解C++的动态绑定与静态绑定的应用详解

    C++是一种强大的面向对象编程语言,它支持两种主要的绑定机制:静态绑定和动态绑定,这两种绑定机制在实现多态性方面起着关键作用。本文将深入探讨这两种绑定方式及其应用。 首先,我们要理解对象的静态类型和动态...

    C++中的静态绑定和动态绑定

    C++在面向对象编程中,存在着静态绑定和动态绑定的定义,本节即是主要讲述这两点区分。  我是在一个类的继承体系中分析的,因此下面所说的对象一般是指一个类的实例。  首先我们需要明确几个名词定义:  静态...

    C++的静态联编和动态联编

    C++中的联编是编程过程中的一个...理解静态联编和动态联编以及它们在C++中的实现机制,对于编写高效、灵活的面向对象程序至关重要。正确使用虚函数和虚析构函数可以避免许多潜在的问题,尤其是在设计复杂类层次结构时。

    吕鑫:【C++语法与数据结构第22天】【第3堂课】动态绑定与静态绑定(面试题)

    1、讲解和演示动态绑定与静态绑定的概念与原理; 2、讲解和演示虚析构函数的概念与原理,并讲解为什么构造函数不能使用虚函数的原因;

    C++的静态联编和动态联编详解

    静态联编是指在编译阶段就将函数实现和函数调用关联起来,因此静态联编也叫早绑定,在编译阶段就必须了解所有的函数或模块执行所需要检测的信息,它对函数的选择是基于指向对象的指针(或者引用)的类型,C语言中,...

    1.继承的本质和原理 2.派生类的构造类型 3.重载、覆盖、隐藏 4.静态绑定和动态绑定 5.多态 vfptr和vftbale

    1.继承的本质和原理 2.派生类的构造类型 ...4.静态绑定和动态绑定 5.多态 vfptr和vftbale 6.抽象类的设计原理 7.多继承以及问题 8.虚基类 vbptr和vbtable 9.RTTI 10.C++四种类型强转 11.继承多态常见笔试面试题分享

    C++ 静态成员变量 嵌套类分配回收内存

    在C++中,动态内存分配和回收通常通过`new`和`delete`操作符来实现。在`Garbage`类的构造函数中,`new`操作符被用来为`CA`类的实例分配内存,而在析构函数中,`delete`操作符则负责释放这部分内存。 这种模式被称为...

    c++调用webservice(包括静态和动态以及webservice源码)

    本篇文章将详细讲解如何在C++中调用WebService,包括静态和动态方式,并探讨相关的源码实现。 首先,让我们理解什么是WebService。WebService是一种基于XML的开放标准,允许不同平台和应用程序之间进行互操作。它...

    C++动态库和静态库的使用.rar

    "LibraryLoad"可能是包含示例代码或示例项目,演示如何在C++项目中加载和使用静态库与动态库。实际操作时,需要根据项目需求和平台特性选择合适的库类型,并遵循上述步骤进行库的创建和使用。 总之,理解并熟练掌握...

    DLL的创建 静态调用 和 动态调用

    2. **编译生成DLL**:使用Visual Studio或其他C++编译器,选择“Win32动态链接库”项目模板,并按照正常的编译步骤生成DLL文件。 3. **头文件**:为了在其他程序中调用DLL的函数,我们需要创建一个头文件,其中包含...

    静态库和动态库_共享库

    总的来说,静态库和动态库是软件开发中不可或缺的部分,它们提供了一种代码复用和模块化的方法,使得程序的开发更加高效和灵活。选择合适的库类型和管理库依赖关系是软件构建过程中的重要环节。

    librdkafka 动态库 静态库

    标题提到的是“librdkafka 动态库 静态库”,这表明我们讨论的核心是librdkafka,一个开源的Apache Kafka C/C++客户端库,它提供了生产者和消费者API,支持高吞吐量的消息传递。动态库和静态库是两种不同的库文件...

    sqlite3 c++ API 静态库

    本资源是针对Visual Studio 2013 X64平台的SQLite3 C++静态库,它允许你在64位环境下直接将SQLite3的功能整合到你的C++项目中,无需额外安装数据库服务器。 SQLite3 C++ API主要包括以下关键知识点: 1. **连接与...

    6多态性_动态联编_多态性讲述_

    相比之下,动态联编,或称晚期绑定、运行时绑定,是指在运行时根据对象的实际类型来决定调用哪个函数。动态联编通过虚函数实现,允许子类重写基类的方法,从而在运行时调用到正确的实现。这种机制使得我们可以使用...

    C++与操作系统等面试题44

    这种方式也被称为**早期绑定**或**静态绑定**。 - **实现方式**:在编译阶段,编译器会根据指向对象的指针或引用的类型来确定调用哪个函数。 - **优点**: - 效率高:因为所有操作都在编译期间完成,所以运行时...

Global site tag (gtag.js) - Google Analytics