您的位置:首页 > 其它

静态联编,动态联编,类指针之间的关系,虚函数与多态性,纯虚函数,虚析构函数

2014-08-27 13:52 435 查看
1.静态联编,是程序的匹配,连接在编译阶段实现,也称为早期匹配。重载函数使用静态联编。

2.动态联编是指程序联编推迟到运行时进行,所以又称为晚期联编。switch语句和if语句是动态联编的例子。

#include<iostream>

void go(int num)
{
}

void go(char *str)
{
}

//class
//::在一个类中
class A
{
public:
void go(int num)
{
}
void go(char *str)
{
}
};

void main()
{
//auto p = go;在编译的阶段就能判断好的,静态联编
void(*p1)(char *str) = go;//指针函数
void(*p2)(int num) = go;  //在编译的时候就确定了的叫静态联编

std::cin.get();
}

//动态联编
void main1()
{
int num;
std::cin >> num;
if (num > 10)
{
system("calc");
}
else
{
system("notepad");
}
}

3.静态联编

   普通成员函数重载可表达为两种形式

   在一个类说明中重载

   基类的成员函数在派生类重载。有3中编译区分方法:

   (1):根据参数的特征加以区分

   (2):使用”::”加以区分

          例如:A::Show();

          有别于B::show()

    (3):根据类对象加以区分

        例如:Aobj.show(); 
调用 
A::Show();

                              
Bobj.show();  调用 
B::Show();

案例:

#include <iostream>
//父类与之类之间的重载,同名函数会覆盖
//即使参数类型不一样,不能直接调用,必须调用父类默认生成的对象来调用
class A
{
public:
void go()
{
std::cout << "A---go";
}

void go(int num)
{
std::cout << "A---go" << num;
}
void go(char *str)
{
std::cout << "A---go" << str << "str";
}
void goA(char *str)
{
std::cout << "A---go" << str << "str";
}
};

class B :public A
{
public:
//const 函数重载一般适用于常量对象
//非const一般适用于变量对象
void go()
{
std::cout << "B---go";
}
void go() const
{
std::cout << "B---go const";
}
};

void main2()
{
B *pb = new B;
//pb->go(NULL);

pb->goA("1");

//当父类和子类中出现了重名的函数的时候,即使参数类型不一样,
//不能直接调用,必须调用父类默认生成的对象来调用。
//pb->go("1");

//C语言中的NULL可以打印,但是C++中的空指针式不可以打印的
pb->A::go(NULL); //当调用
pb->A::go("123");
//pb->A::go(nullptr);//C++空指针不能打印

std::cin.get();
//运行结果是:A---go1strA---go0A---go123str
}

void main()
{
B *p = new B;
p->go();

const B *pb = new B;
pb->go();

std::cin.get();
}

4.类指针的关系

   基类指针和派生类指针与基类对象和派生类对象4种可能匹配。

      A:直接用基类指针引用基类对象。

      B:直接用派生类指针引用派生类对象。

      C:用基类指针引用一个派生类对象。

      D:用派生类指针引用一个基类对象。

5.类与指针之间的关系
      Adynamic适用于虚函数

      B类而言,数据是私有,代码是公有的

      C指针为空,指向一个类,可以直接调用方法
      D涉及内部成员会崩溃,不涉及可以执行
      E父类指针引用父类对象,完全正常引用
      F子类指针引用子类对象,覆盖父类的同名函数
      G父类指针引用子类对象,只能引用父类中的函数
      H子类指针,引用父类对象,子类不涉及内部数据的函数会调用成功
      I涉及到内部数据的会调用成功,执行失败
     J子类指针可以引用父类的不重名的函数
     K子类指针(不是pzi->fu::print();方法)无法引用父类的同名方法
案例如下:

fu.h

#pragma once
#include <iostream>

class fu
{
public:
fu();
~fu();
char * strfu;
void print();
void fufu();
};
zi.h
#pragma once
#include "fu.h"
class zi :
public fu
{
public:
zi();
~zi();
char *strzi;
char ch[900000000];
void print();
void zizi();
};
fu.cpp
#include "fu.h"

fu::fu()
{
this->strfu = "父亲";
std::cout << "fu create" << std::endl;
}

fu::~fu()
{
std::cout << "fu delete" << std::endl;
}

void fu::print()
{
std::cout << this->strfu << "\n";
}

void fu::fufu()
{
std::cout << "我是你爹" << "\n";
}
zi.cpp
#include "fu.h"

fu::fu()
{
this->strfu = "父亲";
std::cout << "fu create" << std::endl;
}

fu::~fu()
{
std::cout << "fu delete" << std::endl;
}

void fu::print()
{
std::cout << this->strfu << "\n";
}

void fu::fufu()
{
std::cout << "我是你爹" << "\n";
}
main.cpp
#include <iostream>

#include"fu.h"
#include "zi.h"

//dynamic适用于虚函数

//类而言,数据是私有,代码是公有的
//指针为空,指向一个类,可以直接调用方法
//涉及内部成员会崩溃,不涉及可以执行

//父类指针引用父类对象,完全正常引用
//子类指针引用子类对象,覆盖父类的同名函数
//父类指针引用子类对象,只能引用父类中的函数
//子类指针,引用父类对象,子类不涉及内部数据的函数会调用成功
//涉及到内部数据的会调用成功,执行失败
//子类指针可以引用父类的不重名的函数
//子类指针(不是pzi->fu::print();方法)无法引用父类
//的同名方法
void main1()
{
{
//fu *pfu = new fu;
//delete pfu;
}
{
//前后一致的不会出现问题
zi *pzi = new zi;
delete pzi;
}
{
//fu *pfu = new zi;
//内存泄漏,理解:后面的空间大,前面的空间小,释放前面,出现内存泄露
//delete pfu;
}
{
//fu *pfu = new fu;
zi *pzi = static_cast<zi *>(new fu);
delete pzi;//内存越界,超过界限释放内存,有时出错,有时无错
}

std::cin.get();
}

void main2()
{
zi *pzi(nullptr);
//会调用自己的函数
pzi->zizi();//结果是:我是你儿子

std::cin.get();
}

void main()
{
fu *pfu = new fu;
zi *pzi = static_cast<zi *>(pfu);
pzi->fufu();//我是你爹

pzi->zizi();//我是你儿子
pzi->fu::print();//父亲

//pzi->print();

//std::cout << pzi->strzi << std::endl;

//pzi->print();
std::cin.get();
}

6.冠以关键字virtual的成员函数称为虚函数。

实现运行时多态的关键首先是要说明虚函数,另外,必须用基类指针调用派生类的不同实现版本。

7.  对于虚函数的总结:

  
A对于继承的情况,如果自来实现了父类的同名函数,

  
B当指针调用的时候会一直调用父类的函数,当成员函数加了virtual

  
C关键字修饰之后,子类才会调用自己的函数。

案例:
#include<iostream>

//总结:对于继承的情况,如果实现了父类的同名函数
//当指针调用的时候会一直调用父类的函数,当成员函数加了virtual关键字后,子类才会调用自己的函数。
class fu
{
public:
virtual void name() //虚函数有4个字节,32位的,实际上是一个函数指针,自动调用子类的函数覆盖虚函数
{
std::cout << "父类";
std::cout << "x=" << x << "\n";
}
int x;
fu(int a) :x(a)
{
}
};

class zi :public fu
{
public:
void name()
{
std::cout << "子类";
std::cout << "x=" << x << ",y=" << y << "\n";
}
int y;
zi(int a, int b) :fu(a), y(b)
{

}
};

class sun :public zi
{
public:
void name()
{
std::cout << "孙类";
std::cout << "x=" << x << ",y=" << y << ",z=" << z << "\n";
}
int z;
sun(int a, int b, int c) :zi(a, b), z(c)
{
}
};

int main(int argc, char *argv[])
{
//下面的结果为8,说明虚函数的大小为4字节
std::cout << sizeof(fu) << std::endl;
fu fu1(1);
zi zi1(2, 3);
sun sun1(4, 5, 6);
fu *pfu;
pfu = &fu1;
pfu->name();//打印出:父类x=1

pfu = &zi1;
pfu->name();//父类加了virtual之后,此处打印出:子类x=2,y=3

pfu = &sun1;
pfu->name();//父类加了virtual之后,此处打印出:孙类x=4,y=5

std::cin.get();
}

8:纯虚函数



#include <iostream>

using namespace std;

//因为base其中有纯虚函数,所以不能实例化了。
class base
{
public:

int num;
void goA()
{
}
//下面是一个纯虚函数
virtual void show()=0; //带了纯虚函数就是抽象类
//可以有实现,也可以没有实现,可以放在内部外部
};

class run:public base
{
public:
void show()
{
std::cout << "run show();" << std::endl;
}
};

int main()
{
cout << "Hello World!" << endl;
//base base1;抽象类无法实例化
run runInstance;
runInstance.show();
return 0;
}
运行结果:



案例2:

#include<iostream>

class base
{
public:
//纯虚函数,有无定义都可以
//有一个纯虚函数,都是抽象类,无法实例化
virtual void run() = 0 //限定一个类不能实例化,作为专门的接口,QT里面不可以在内部定义。
{
std::cout << "base run\n";
}
virtual ~base()
{
}
};

//抽象类不可以用于函数的参数以及返回值类型
//抽象类指针是可以
base * test(base *p)
{
base *pbase(nullptr);
return pbase;
}

class boy :public base
{
public:
void run()
{
std::cout << "男孩奔跑\n";
}
};

class girl :public base
{
public:
void run()
{
std::cout << "女孩奔跑\n";
}
};

void main()
{
//抽象类无法实例化对象,可以实话指针
//纯虚函数与抽象类与虚函数起到接口的作用
//用同一个接口完成不同的功能
//纯虚函数完全就是为了接口的存在,有了纯虚函数的类无法实例化
//虚函数占4个字节,就是指针,函数指针
boy boy1;
girl girl1;
base *p(nullptr);
p = &boy1;
p->run();
p = &girl1;
p->run();

std::cin.get();
}

9.虚析构函数,在析构函数的前面加上virtual

案例代码如下:

#include <iostream>

using namespace std;

class A
{
public:
//构造函数不可以是虚函数,如果是了就不可以再构造,
//没有办法创建子类中的父类对象
A()
{
std::cout << "a create" << std::endl;
}
//虚析构函数,让父类指针正确的释放子类对象的内存
virtual ~A()
{
std::cout << "a delete" << std::endl;
}
};

class B:public A
{
public:
B()//B创建自动调用A的构造函数
{
std::cout << "b create" << std::endl;
}
~B()//B析构的时候会自动调用A的析构函数
{
std::cout << "b delete" << std::endl;
}
};

int main()
{
A *p = new B;
delete p;
return 0;
}

如果析构函数前没有加virtual,运行结果如下:




如果析构函数前加了virtual,运行结果如下:



10.
者多个虚函数,或者多个纯虚函数都占四个字节

案例如下:

#include <iostream>

using namespace std;

//抽象类也可以实现继承
//仅有一个指针指向虚函数表

//1个或者多个虚函数,或者多个纯虚函数都占四个字节
//一个指针存储了虚函数标的地址

class basebase
{
public:
virtual void show() = 0;
virtual void hide() = 0;
virtual void run() = 0;
};

class base
{
public:
virtual void show(){}
virtual void hide(){}
virtual void run(){}
};

int main()
{
cout << sizeof(basebase) << endl;//结果是4
cout << sizeof(base) << endl;//结果为4
return 0;
}

11.子类只有都实现了基类中的纯虚函数之后才可以实例化

案例说明如下:

#include "mainwindow.h"
#include <QApplication>
#include<QPushButton>
#include<QLabel>
#include<iostream>

//抽象类也可以实现继承
class basebase
{
public:
virtual void show()=0;
virtual void hide()=0;
};

//接口,操作不同的类对象的方法
class base :public basebase
{
public:
virtual void resize(int x,int y)=0;
virtual void move (int cx,int cy)=0;
};

class myself: public base
{
public:
//只要有一个接口的没有实现,抽象类
//把所有就接口都实现了的类才可以实例化
void show(){}
void hide(){}
};

class mydialog: public base
{
public:
MainWindow w;
void show()
{
w.show();
}

void hide()
{
w.hide();
}

void resize(int x,int y)
{
w.resize(x,y);
}

void move (int cx,int cy)
{
w.move(cx,cy);
}
};

class mybutton: public base
{
public:
QPushButton w;
void show()
{
w.show();
}

void hide()
{
w.hide();
}

void resize(int x,int y)
{
w.resize(x,y);
}

void move (int cx,int cy)
{
w.move(cx,cy);
}
};

class mylabel: public base
{
public:
QLabel w;
void show()
{
w.show();
}

void hide()
{
w.hide();
}

void resize(int x,int y)
{
w.resize(x,y);
}

void move (int cx,int cy)
{
w.move(cx,cy);
}
};

int main(int argc, char *argv[])
{
QApplication a(argc, argv);

//myself my1;
return a.exec();
}

int main1(int argc, char *argv[])
{
QApplication a(argc, argv);
mydialog dialog1;
mybutton button1;
mylabel label1;
//只有在.pro中加上CONFIG += c++11后nullptr才可以使用,因为其是C++11特性
base *pbase(nullptr);
pbase =&dialog1;
pbase->show();
pbase->resize(100,200);
pbase =&button1;
pbase->show();
pbase->resize(200,200);
pbase=&label1;
pbase->show();
pbase->resize(300,200);

return a.exec();
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: 
相关文章推荐