C++ 第七天

day07
一、继承中构造和析构的调用
1.1调用顺序
构建子类对象时 一定会先调用父类的构造函数
再调用自己的构造函数
析构函数的调用和构造函数调用的顺序相反。
#include <iostream>
using namespace std;
class A{
public:
A(){
cout << "A()" << endl;
}
~A(){
cout << "~A()" << endl;
}
};

class B:public classA{
public:
B(){
cout << "B()" << endl;
}
~B(){
cout << "~B()" << endl;
}
};
int main(){
B b;
}
1.2 如果父类有多个构造函数 子类默认调用父类的无参构造函数
子类还可以指定调用父类的构造函数
可以使用初始化参数列表 指定调用父类的构造函数
#include <iostream>
using namespace std;
class A{
public:
A(){
cout << "A()" << endl;
}
A(int x){
cout << "A(int)" << endl;
}
~A(){
cout << "~A()" << endl;
}
};

class B:public classA{
public:
B():A(1){
cout << "B()" << endl;
}
~B(){
cout << "~B()" << endl;
}
};
int main(){
B b;
}
二、继承中 拷贝构造和赋值运算符的调用
不能被继承的函数:构造 析构 拷贝构造 赋值运算符
构建子类对象时 子类默认调用父类的拷贝构造函数和赋值运算符
但子类一旦提供自己的拷贝构造和赋值运算符,则不再调用父类的 需要指定调用
#include <iostream>
using namespace std;
class Animal{
public:
Animal(){
}
Animal(const Animal& a){
cout << "Animal(const Animal&)" << end;
}
Animal& operator=(const Animal& a){
cout << "operator(const Animal)" << endl;
}
};
class Cat:public Animal{
public:
Cat(){
}
Cat(const Cat& cat):Animal(cat){
cout << "Cat(const Cat&)" << endl;
}
Cat& operator=(const Cat& cat){
/*使用类名::区分*/
Animal::operator=(cat);
cout << "operator=(Cat&)" << endl;
return *this;
}
};
int main(){
Cat cat;
Cat cat2;//=cat;
/*Cat cat2=cat;拷贝构造*/
cat2=cat;
}
三、名字隐藏机制(name hide)
3.1 在继承中如果子类提供了和父类同名的数据则子类的数据会把父类的数据隐藏掉
#include <iostream>
using namespace std;
class A{
public:
int x;
void show(){
cout << x << endl;
}
};
class B:public A{
public:
int x;
void show(){
cout << "B show()" << endl;
}
};
int main(){
B b;
b.x=101;
b.show();
/*要调用A中对应的show*/
b.A::show();
}
3.2 写一个父类 这个父类中有一个静态成员变量
static int x;
再写一个子类 继承这个父类 测试静态成员变量有没有名字隐藏机制
#include <iostream>
using namespace std;
classA{
public:
static int x;
};
/*
class B:public A{

};
*/
class B:public A{
public:
static int x;
};
int A::x=3;
int B::x=100;
int main(){
cout << A::x << endl;
cout << B::x << endl;
cout << B::A::x << endl;
}

四、多继承
4.1 一个类 可以有多个直接父类
4.2 语法
class D:public A,private B,public C{
};
#include <iostream>
using namespace std;
class Phone{
double price;
public:
double getPrice(){
return price;
}
Phone(double price=0.0):price(price){
cout << "Phone()" << endl;
}
void phone(){
cout << "call " << endl;
}
};

class Camera{
double price;
public:
double getPrice(){
return price;
}
Camera(double price=0.0):price(price){
cout << "Camera()" << endl;
}
void camera(){
cout << "camera" << endl;
}
};

class Mp3{
double price;
public:
double getPrice(){
return price;
}
Mp3(double price=0.0):price(price){
cout << "Mp3()" << endl;
}
void mp3(){
cout << "Mp3" << endl;
}
};

class IPhone:public Phone,public Camera,public Mp3{
/*构造只和继承顺序有关*/
public:
IPhone(double p=0,double c=0,double m=0):Phone(p),Camera(c),Mp3(m){

}
/*名字隐藏机制*/
double getPrice(){
return Phone::getPrice()+Camera::getPrice()+Mp3::getPrice()
}
};

int main(){
/*Phone phone(999);
phone.phone();
cout << phone.getPrice() << endl;*/
IPhone iphone6(999,51,3000);
iphone6.phone();
iphone6.camera();
iphone6.Mp3::getPrice();//类名作用域
iphone6.getPrice();
}
4.4多继承容易引入冲突
a. 类名作用域 + 名字隐藏机制
b. 1.抽取共同的成员变量和成员函数到更高层类中
2.然后采用虚继承
对直接的子类而言没有明显的变化 还是会把父类的数据复制下来。
但对孙子类而言共同的部分 不再从父类中复制 而是从更高层的类中
复制一份数据。
使用指针维护一份数据
#include <iostream>
using namespace std;
class Product{
double price;
public:
double getPrice(){
return price;
}
Product(double price=0.0)::price(price){
}
};
class Phone:virtual public Product{
public:
Phone(double price=0.0):Product(price){
cout << "Phone()" << endl;
}
void phone(){
cout << "call " << endl;
}
};

class Camera:virtual public Product{
public:
Camera(double price=0.0):Product(price){
cout << "Camera()" << endl;
}
void camera(){
cout << "camera" << endl;
}
};

class Mp3:virtual public Product{
public:
Mp3(double price=0.0):Product(price){
cout << "Mp3()" << endl;
}
void mp3(){
cout << "Mp3" << endl;
}
};

class IPhone:public Phone,public Camera,public Mp3{
public:
IPhone(double p=0,double c=0,double m=0):Product(p+m+c){

}
};

int main(){
cout << sizeof(Phone) << endl; //12
cout << sizeof(Camera) << endl; //12
Camera camera(222);
cout << camera.getPrice() << endl;
IPhone iphone6(1500,51,3300);
cout << iphone6.getPrice() << endl;
cout << sizeof(IPhone) << endl;//20
}

五、多态
5.1 概念
当父类型指针(引用) 指向(引用)子类对象时,调用父类型中的定义的虚函数,
如果子类覆盖了父类的虚函数 则调用的表现是子类的否则是父类的。

继承是构成多态的基础
虚函数是关键
函数重写(over write)是必备条件

5.2 虚函数
如果一个成员函数 加了virtual 修饰,则这个函数成为虚函数。
虚表指针
class A{
public:
/*这是虚函数*/
virtual void show(){}
};
#include <iostream>
using namespace std;
class A{
double x;
public:
virtual void show(){
cout << "show()" << endl;
}
virtual void run(){
cout << "run()" << endl;
}
};
int main(){
cout << sizeof(A) << endl; //12与虚函数个数无关;去掉virtual为8
}
5.3 函数重写
5.3.1
在子类中提供了和父类同名的函数名 并且这个函数必须在父类中是虚函数
要求函数名相同 参数列表 返回值也必须相同。
否则就是名字隐藏。
5.3.2
函数重写:子类提供和父类同名的虚函数
要求函数名 参数列表 返回值相同
函数重载:同一作用域中 函数名相同
参数列表不同的函数构成重载关系。
名字隐藏:子类提供和父类同名的数据
就会把父类的数据隐藏掉(虚函数除外)
#include <iostream>
using namespace std;
class A{
public:
void show(){
cout << "show()" << endl;
}
virtual void run(){
cout << "run()" << endl;
}
};

class B:public A{
public:
/*名字隐藏name hide*/
void show(){
cout << "this is show()" << endl;
}
/*函数重写over write*/
virtual void run(){
cout << "this is run()" << endl;
}
};
int main(){
A *a=new B();
a->show();
}
5.4 多态的应用
函数参数
#include <iostream>
using namespace std;
class Animal{
public:
void show(){
cout << "Animal show()" << endl;
}
virtual void run(){
cout << "Animal run()" << endl;
}
}

class Dog:public Animal{
public:
void run(){
cout << "Dog run()" << endl;
}
};

class Bird:public Animal{
public:
void run(){
cout << "Bird run()" << endl;
}
};

class Fish:public Animal{
public:
void run(){
cout << "Fish run()" << endl;
}
};

/*类型通用 损失个性*/
void testAnimal(Animal& a){
a.run();
}

int main(){
Dog dog;
Fish fish;
Bird bird;
testAnimal(dog);
testAnimal(fish);
testAnimal(bird);
Animal *a=getA(0);
a->run();
}

函数返回值
Animal* getA(int x){
if(0 == x){
return new Dog();
}else if(1 == x){
return new Fish();
}else {
return new Bird();
}
}
5.5 多态的底层实现
虚函数
虚函数表指针
虚函数表

原文地址:https://www.cnblogs.com/Malphite/p/9980380.html