作者:dghghjkk_952 | 来源:互联网 | 2023-10-10 12:56
在上图中,c继承b,b集成a。在classA中包含m_data1和m_data2以及一个指针。ClassB,继承了A,因此B中除了自己的m_data3外,还包含了classA的所有内容,cla
在上图中,c继承b,b集成a。在class A 中包含m_data1和m_data2以及一个指针。
Class B,继承了A,因此B中除了自己的m_data3外,还包含了class A的所有内容,class C也同理。
在一个类中,若有一个虚函数,内存中有一个指针,若有一万个虚函数,内存中依然有一个指针
在继承关系中,子类不仅继承了父类的所有数据,也继承了父类的函数,准确的说是父类函数中的调用权。没有人可以说清楚父类中的函数占用多大的内存。
在上图右边,class A有2个虚函数,2个普通函数,因此,class B中也同样拥有两个虚函数(继承),但是B中重写了其中一个虚函数。另外B中也有一个普通函数(虽然与父类同名,但是是两个不同的函数)class C同理。
因此在ABC三个类中,共有4个虚函数4个普通函数
Class A中的虚指针指向一个虚表(vtbl),虚表中存放的都是函数指针,指向虚函数存放的位置。Class A中有两个虚函数,因此虚表中就有两个指针分别指向两个虚函数。
当我们new一个class C的时候就会产生一个指向class C 的指针p,如果我们想通过指针p调用class C的一个虚函数应该怎么调用呢?
思路是这样的,通过指针p找到虚表,然后通过虚表中该函数的位置n(编译时函数出现的顺序),再找到该函数。
总结:满足以下条件,即动态绑定:a. 指针b. 向上转型(指针指的是子类)c.调用虚函数
向上转型解释:例如,class B 继承A。A* pa=new B; pa是指向子类B的指针,但pa是A的对象,由子类B向A转型。
Const 再谈
对于数据,我们有const和non-const两种,对于成员函数,我们也有const和non-const两种。在这种情况下,这四种东西有如下表所示的关系:
在我们设计成员函数的时候,若我们本意是不改变数据而忘了加const的时候,在调用成员函数而对于object加了const的时候(常量对象调用非常量函数),就会发生冲突而导致错误。
New 和 Delete
Array new 一定要搭配array delete
可以重载operator new、operator delete、operator new[]、operator delete[]
Inline void* operator new (size_t size){ }
Inline void* operator new [](size_t size){}
Inline void operator delete (void* ptr){ }
Inline void operator delete [] (void* ptr){}
本周作业体会
本周作业分为两个部分
(1) 是在上周的基础上添加构造函数和析构函数,然后观察构造和析构函数的调用过程。
这里头文件代码设计如下:
#ifndef__FRUIT__
#define__FRUIT__
#include
usingnamespace std;
classFruit
{
int no;
double weight;
char key;
public:
Fruit() { cout <<"The defaultFruit ctor.this= "
<
virtual ~Fruit() {
cout <<"The Fruitdtor.this= "
<
}
void print(){}
virtual void process(){}
};
classApple :public Fruit
{
int size;
char type;
public:
Apple(){cout<<"The default Applector.this= "
<
virtual ~Apple() {
cout <<"The Appledtor.this= "
<
}
void save(){}
virtual void process(){}
};
#endif
源代码如下:
#include
#include"week_5.h"
intmain()
{
Fruit my_fruit;
cout <<"*************************" <
Fruit *p = new Fruit();
delete p;
cout <<"*************************" <
Apple my_apple;
cout <<"*************************" <
Fruit *q = new Apple();
delete q;
cout <<"*************************" <
Apple *x = new Apple();
delete x;
}
在测试代码中分别设计了五种对象的创建
A) 在栈中创建fruit,
B) 在堆中创建fruit
C) 在栈中创建apple
D) 在堆中创建apple,用父类指针指向它
E) 在堆中创建apple,用子类指针指向它
经编译,结果如下;
结果分析如下:
A) 在栈中创建父类对象时,调用父类构造函数,其析构函数在程序最终结束前才进行调用
B) 在堆中创建父类对象时,调用父类构造函数,再调用析构函数
C) 在栈中创建子类对象时,先调用父类构造函数,再调用子类构造函数,指针指向相同地址。调用析构时同样发生在程序结束时,先调用子类析构函数,再调用父类析构函数。最后调用的析构函数是最先调用的构造函数。
D) 和E)中在堆中创建子类对象时,先调用父类构造函数,再调用子类构造函数,指针指向相同地址,接着先调用子类析构函数,再调用父类析构函数
在D和E中发生的事情一模一样,但是在堆中创建apple,用父类指针指向它时,属于upcast。
(1) 作业第二部分为Apple类重载::operator new 和 ::operator delete,并观察调用结果。
主程序如下:
intmain()
{
Fruit my_fruit;
cout <<"~~~~~~~~~~~~~~~~~~~~~~~~~~~~" <
Apple my_apple;
cout <<"~~~~~~~~~~~~~~~~~~~~~~~~~~~~" <
Fruit* p = new Fruit();
delete p;
cout <<"~~~~~~~~~~~~~~~~~~~~~~~~~~~~" <
Fruit* q = new Apple();
delete q;
cout <<"~~~~~~~~~~~~~~~~~~~~~~~~~~~~" <
Apple* qq = new Apple[5];
delete[] qq;
cout <<"~~~~~~~~~~~~~~~~~~~~~~~~~~~~" <
Fruit** wk = new Fruit*[5];
for (int i = 0; i <5; i++)
{
wk[i] = new Apple();
}
for (int i = 0; i <5; i++)
{
delete wk[i];
}
delete wk;
return 0;
}
头文件如下:
#ifndef__FRUIT__
#define__FRUIT__
#include
usingnamespace std;
classFruit
{
int no;
double weight;
char key;
public:
Fruit() { cout <<"The defaultFruit ctor.this= "
<
virtual ~Fruit() {
cout <<"The Fruitdtor.this= "
<
}
void print(){}
virtual void process(){}
};
classApple :public Fruit
{
int size;
char type;
public:
Apple(){cout<<"The default Applector.this= "
<
virtual ~Apple() {
cout <<"The Appledtor.this= "
<
}
void save(){}
virtual void process(){}
static void* operator new(size_t size);
static void operator delete(void* ptr,size_tsize);
static void* operator new[](size_t size);
static void operator delete[](void*ptr,size_t size);
};
inline
void*Apple::operator new(size_t size)
{
Apple* p = (Apple*)malloc(size);
cout <<"Apple::new()_size= "<
return p;
}
inline
voidApple::operator delete(void* ptr, size_t size)
{
cout <<"Apple::delete()_size=" <
return p;
}
inline
voidApple::operator delete[](void* prt, size_t size)
{
cout <<"Apple::delete[]()_size=" <