继承中的对象模型
#include <iostream>
#include <string>
#include <string.h>
#include <stdlib.h>
using namespace std;
class Aclass
{
public:
int mA;
int mA1;
};
class Bclass :public Aclass
{
public:
int mB;
};
class Cclass : public Bclass
{
public:
int mC;
};
void test01()
{
cout << sizeof(Aclass) <<endl;
cout << sizeof(Bclass) <<endl;
cout << sizeof(Cclass) <<endl;
}
int main()
{
test01();
return 0;
}
对象构造和析构的调用
继承中的构造和析构
1、子类对象在创建时会首先调用父类的构造函数,父类构造函数执行完毕后,才会调用子类的构造函数
2、当父类构造函数有参数时,需要在子类初始化列表(参数列表)中显示调用父类构造函数
3、析构函数调用顺序和构造函数相反
#include <iostream>
#include <string>
#include <string.h>
#include <stdlib.h>
using namespace std;
class Base
{
public:
Base(int age, string name)
{
this->age = age;
this->name = name;
cout <<"Base..gouzao"<<endl;
}
~Base()
{
cout <<"Base..xigou"<<endl;
}
int age;
string name;
};
// 创建子类对象时,必须先构建父类。需要调用父类的构造函数
class son:public Base
{
public:
son(int id, int age, string name):Base(age, name)
{
this->id = id;
cout <<"son..gouzao"<<endl;
}
~son()
{
cout <<"son..xigou"<<endl;
}
int id;
};
void test01()
{
son p(1, 18, "lucy");
}
int main()
{
test01();
return 0;
}
执行结果:
Base…gouzao
son…gouzao
son…xigou
Base…xigou
继承中同名成员的处理
当子类成员和父类成员同名时,子类依然从父类继承同名成员
如果子类有成员和父类同名,子类访问其成员默认访问子类的成员(本作用域,就近原则)
在子类通过作用域 :: 进行同名成员区分(在派生类中使用基类的同名成员,显示使用类名限定符)
#include <iostream>
#include <string>
#include <string.h>
#include <stdlib.h>
using namespace std;
class Base
{
public:
Base(int a)
{
this->a = a;
}
int a;
void foo()
{
cout <<"Base.. foo"<<endl;
}
};
class son:public Base
{
public:
son(int a1, int a2):Base(a1), a(a2)
{}
void foo()
{
cout <<"son.. foo"<<endl;
}
int a;
};
void test01()
{
son p(2,3);
p.foo(); // son.. foo
cout<< p.a << endl; // 3
cout << p.Base::a << endl; // 2 通过子类对象 访问到父类中的同名成员 需要加作用域
}
int main()
{
test01();
return 0;
}
菱形继承和虚拟机
…
…
多态的概念
一种接口,多种形态
- 静态多态
- 编译时,地址早绑定(静态联编) foo(int) 、 foo()
- 动态多态
- 运行时,才确定需要调用的地址(动态联编)
发生多态的四个条件
1、父类中有虚函数
2、必须发生继承
3、子类必须重写虚函数(函数的返回值、函数名、参数一致,函数内容[函数体]不一致)
4、父类的指针或引用指向子类的对象
#include <iostream>
#include <string>
#include <string.h>
#include <stdlib.h>
using namespace std;
class Animal
{
public:
virtual void speak() // 虚函数
{
cout <<"Animal speak" <<endl;
}
};
class Dog:public Animal
{
public:
// 重写 虚函数
void speak()
{
cout <<"Dog speak" <<endl;
}
};
// 如果两个类发生了继承,父类和子类在编译器中会自动转换,不需要人为转换
void do_work(Animal &obj)
{
obj.speak(); // 地址早绑定 ; 进行virtual后 地址晚绑定
}
void test01()
{
Animal p1;
do_work(p1); // Animal speak
Dog p2;
do_work(p2); // Dog speak
}
int main()
{
test01();
return 0;
}
案例2:动态实现计算器案例
#include <iostream>
#include <string>
#include <string.h>
#include <stdlib.h>
using namespace std;
class Cacl
{
public:
virtual int mycacl(int a1, int b1) // 虚函数
{
return 0;
}
};
class Add:public Cacl
{
public:
// 重写 虚函数
int mycacl(int a1, int b1)
{
return a1 + b1;
}
};
class Sub:public Cacl
{
public:
// 重写 虚函数
int mycacl(int a1, int b1)
{
return a1 - b1;
}
};
int do_work(Cacl &obj, int a, int b)
{
return obj.mycacl(a,b);
}
void test01()
{
Add p1;
cout << do_work(p1, 1, 2) << endl; // 3
Sub p2;
cout << do_work(p2, 1, 2) << endl; // -1
}
int main()
{
test01();
return 0;
}
纯虚函数、抽象类
纯虚函数:将虚函数等于0,实质是将虚函数表的函数入口地址置为NULL
抽象类:一个类中如果有纯虚函数,那么这个类就是一个抽象类,抽象类不能实例化对象。继承抽象类的子类也是一个抽象类。如果子类重写了虚函数,那么子类就不是抽象类。
#include <iostream>
#include <string>
#include <string.h>
#include <stdlib.h>
using namespace std;
/*
class Cacl
{
public:
virtual int mycacl(int a1, int b1) // 虚函数
{
return 0;
}
};
*/
// 如果有纯虚函数的类,叫做抽象类。抽象类不能实例化对象
class Cacl
{
public:
virtual int mycacl(int a1, int b1) =0; // 虚函数等于0 ==> 纯虚函数
};
class Mod:public Cacl
{
// 子类继承了抽象类 那么子类也是一个抽象类
};
class Add:public Cacl
{
public:
// 重写 虚函数, 子类重写类虚函数,子类就不是抽象类了
int mycacl(int a1, int b1)
{
return a1 + b1;
}
};
class Sub:public Cacl
{
public:
// 重写 虚函数
int mycacl(int a1, int b1)
{
return a1 - b1;
}
};
int do_work(Cacl &obj, int a, int b)
{
return obj.mycacl(a,b);
}
void test01()
{
// Cacl p;
Add p1;
cout << do_work(p1, 1, 2) << endl; // 3
Sub p2;
cout << do_work(p2, 1, 2) << endl; // -1
}
int main()
{
test01();
return 0;
}
虚析构
虚析构 作用:在调用基类的析构函数之前,会先调用子类的析构函数
#include <iostream>
#include <string>
#include <string.h>
#include <stdlib.h>
using namespace std;
class Animal
{
public:
virtual void speak() // 虚函数
{
cout <<"Animal speak" <<endl;
}
virtual ~Animal() // 虚析构 作用:在调用基类的析构函数之前,会先调用子类的析构函数
{
cout <<"Animal xigou" <<endl;
}
};
class Dog:public Animal
{
public:
// 重写 虚函数
void speak()
{
cout <<"Dog speak" <<endl;
}
~Dog()
{
cout <<"Dog xigou" <<endl;
}
};
// 如果两个类发生了继承,父类和子类在编译器中会自动转换,不需要人为转换
void do_work(Animal &obj)
{
obj.speak(); // 地址早绑定 ; 进行virtual后 地址晚绑定
}
void test01()
{
// Animal p1;
// do_work(p1); // Animal speak
// Dog p2;
// do_work(p2); // Dog speak
Animal *p = new Dog;
p->speak();
delete p;
}
int main()
{
test01();
return 0;
}