封装
封装是将现实生活中的事物定义为类,将事物的数据抽象为属性,将事物的行为抽象为方法。
封装的关键字是class。
继承
子类继承父类的属性和方法,使得子类具备父类的特征。这样可以实现代码重用。
定义类时可以从现有类继承,被继承的类叫父类或超类、基类;新定义的类叫子类或派生类。子类中不需要定义父类中已有的属性和方法,只需要定义父类没有而子类新增的成员。
类的继承类型
单继承,子类只有一个基类。
多继承,子类有多于一个基类。
直接继承,教师类是人类的直接继承;人类是教师类的直接基类。
间接继承,教师管理人员类是人类的间接继承;人类是教师管理人员类的间接基类。
方法的隐藏(重定义)
子类中定义和父类方法名完全相同的方法时,子类的函数屏蔽与其同名的父类函数,这叫方法的隐藏。
#include <iostream>
#include "Pet.h"
#include "Cat.h"
#include "Dog.h"
using namespace std;
int main()
{
Pet pet("皮卡", 3);
pet.barking();
pet.running();
pet.barking(3);
Cat cat("叮当", 5);
cat.barking();
cat.running();
cat.barking(3);
Dog dog("旺财", 8);
dog.barking();
dog.running();
dog.guardHouse();
/*
因为Dog 定义了barking(),其父类Pet中的barking()和barking(int n)
都被隐藏了,所以Dog的对象不能使用barking(int n)方法。
*/
// dog.barking(3);
return 0;
}
类的继承方式
//Pet.h
#pragma once
class Pet
{
//protected修饰的数据成员和成员函数,允许本类和本类的派生类(子类)的成员函数访问,对类外部不可见。
protected:
char m_name[20];
int m_age;
public:
Pet(const char* name, int age);
void running();
void barking();
void barking(int n);
};
//Pet.c
#include "Pet.h"
#include <iostream>
/*#include <iomanip> strcpy_s等字符串处理函数包含在这个库内。不导入iostream时可以导入iomanip。*/
using namespace std;
Pet::Pet(const char* name, int age)
{
strcpy_s(m_name, 20, name);
m_age = age;
}
void Pet::running()
{
cout << m_name << "在跑" << endl;
}
void Pet::barking()
{
cout << m_name << "在叫" << endl;
}
void Pet::barking(int n)
{
cout << m_name << "叫了" << n << "声" << endl;
}
//Bird.h
#pragma once
#include "Pet.h"
/*
private继承方式
Bird private方式继承Pet,
Bird可以访问Pet的public或protected属性和方法,
但是其子类不能访问Pet的任何属性和方法。
*/
class Bird : private Pet
{
public:
Bird(const char* name, int age);
void action();
};
//Bird.c
#include "Bird.h"
Bird::Bird(const char* name, int age) : Pet(name, age)
{
}
/*
由于Fish private继承自 Pet, Pet的方法不能被外部访问,
但是能够被Fish的方法访问。
*/
void Bird::action()
{
running();
barking();
}
//Pigeon.h
#pragma once
#include "Bird.h"
class Pigeon : public Bird
{
public:
Pigeon(const char* name, int age);
void fly();
};
//Pigeon.c
#include "Pigeon.h"
#include <iostream>
using namespace std;
Pigeon::Pigeon(const char* name, int age) : Bird(name, age)
{
}
void Pigeon::fly()
{
/*
由于Pigeon的父类Bird采用private方式继承Pet,
Brid继承到的barking()等方法,访问权限从public变成了private
Brid继承到的m_name等属性,访问权限从protected变成了private,
Pigeon类中既不能访问Pet的方法,也不能访问Pet的属性。
barking();
cout << m_name << "在游泳" << endl;
*/
}
//Cat.h
#pragma once
#include "Pet.h"
/*
声明Cat类继承自Pet类;
Cat类是Pet类的子类或派生类;
Pet类是Cat类的父类、基类或超类。
*/
class Cat : public Pet
{
public:
// 派生类不继承父类的构造函数,需要至少实现1个父类类构造函数。
Cat(const char* name, int age);
};
//Cat.c
#include "Cat.h"
/*
子类构造函数必须先执行父类构造函数,
子类的构造函数的构造列表中包含一个父类构造函数。
*/
Cat::Cat(const char* name, int age) : Pet(name, age)
{
}
//Dog.h
#pragma once
#include "Pet.h"
class Dog : public Pet
{
public:
Dog(const char* name, int age);
void guardHouse();
void barking();
};
//Dog.c
#include <iostream>
#include "Dog.h"
using namespace std;
Dog::Dog(const char* name, int age) : Pet(name, age)
{
}
void Dog::guardHouse()
{
cout << m_name << "在看门" << endl;
}
void Dog::barking()
{
cout << m_name << "汪汪叫" << endl;
}
//Fish.h
#pragma once
#include "Pet.h"
/*
protected继承方式
Fish protected方式继承Pet,
Fish及其子类可以访问Pet的public或protected属性和方法。
*/
class Fish : protected Pet
{
public:
Fish(const char* name, int age);
void action();
};
//Fish.c
#include "Fish.h"
Fish::Fish(const char* name, int age) : Pet(name, age)
{
}
/*
由于Fish protected继承自 Pet, Pet的方法不能被外部访问,
但是能够被Fish的方法访问。
*/
void Fish::action()
{
running();
barking();
}
//Whale.h
#pragma once
#include "Fish.h"
class Whale : public Fish
{
public:
Whale(const char* name, int age);
void swimming();
};
//Whale.c
#include "Whale.h"
#include <iostream>
using namespace std;
Whale::Whale(const char* name, int age) : Fish(name, age)
{
}
void Whale::swimming()
{
barking();
cout << m_name << "在游泳" << endl;
}
//类的继承方式
#include <iostream>
#include "Pet.h"
#include "Fish.h"
#include "Bird.h"
#include "Whale.h"
using namespace std;
int main()
{
Pet pet("皮卡", 3);
pet.barking();
pet.running();
pet.barking(3);
Fish fish("食人鱼", 3);
/*
由于Fish protected继承自 Pet, Pet的方法不能被外部访问
fish.barking();
fish.running();
fish.barking(3);
*/
fish.action();
Bird bird("食人鸟", 3);
/*
由于Brid protected继承自 Pet, Pet的方法不能被外部访问
bird.barking();
bird.running();
bird.barking(3);
*/
bird.action();
Whale whale("杀人鲸", 2);
whale.action();
whale.swimming();
return 0;
}
派生类的构造和析构过程
派生类的构造函数执行顺序
调用基类构造函数
调用派生类构造函数
派生类的析构函数执行顺序
执行派生类析构函数
执行基类析构函数
#include <iostream>
using namespace std;
class Animal
{
protected:
char m_type[20];
public:
Animal(const char* type)
{
cout << type << "Animal 构造中" << endl;
strcpy_s(m_type, 20, type);
}
void show()
{
cout << "Animal: " << m_type << endl;
}
~Animal()
{
cout << "Animal析构中" << endl;
}
};
class Tiger : public Animal
{
private:
int m_weight;
public:
Tiger(const char* type, int weight) : Animal(type)
{
cout << type << "Tiger 构造中" << endl;
m_weight = weight;
}
void show()
{
cout << "Tiger: " << m_type << ", "<< m_weight << endl;
}
~Tiger()
{
cout << "Tiger析构中" << endl;
}
};
int main()
{
Animal animal("大鹅");
animal.show();
Tiger tiger("大虎", 200000);
tiger.show();
// 父类指针可以指向子类对象
Animal* p = &animal;
p->show();
p = &tiger;
p->show();
return 0;
}
多继承简介
一个派生类可以有多于一个基类,称之为多继承。
多继承派生类的构造顺序是按照基类声明顺序构造基类,所有基类构造函数执行完毕后,执行派生类构造函数。析构顺和构造顺序相反。
多继承派生类的每个基类都应该指定继承类型。
当多个基类存在同名成员时, 使用 基类名::成员名 访问基类对应的成员。
#include <iostream>
using namespace std;
// 定义基类A
class BaseA
{
protected:
int m_a;
int m_c = 0;
public:
BaseA(int a)
{
cout << "BaseA构造中" << endl;
m_a = a;
}
~BaseA()
{
cout << "BaseA析构中" << endl;
}
};
// 定义基类B
class BaseB
{
protected:
int m_b;
int m_c = 10;
public:
BaseB(int b)
{
cout << "BaseB构造中" << endl;
m_b = b;
}
~BaseB()
{
cout << "BaseB析构中" << endl;
}
};
// 定义派生类Derived,共有继承自BaseA和BaseB。
class Derived : public BaseB, public BaseA // 多继承按照声明顺序依次调用基类构造函数
{
public:
Derived(int a, int b) : BaseA(a), BaseB(b)
{
cout << "Derived构造中" << endl;
}
~Derived()
{
cout << "Derived析构中" << endl;
}
void show()
{
cout << "m_a: " << m_a << " m_b: " << m_b << endl;
// 当多个基类存在同名成员时, 使用 基类名::成员名 访问基类对应的成员。
cout << "BaseA::m_c: " << BaseA::m_c << " BaseB::m_c" << BaseB::m_c << endl;
}
};
int main()
{
Derived derived(1, 2);
derived.show();
return 0;
}
多态
多态的一般含义是一个名字有多种具体的解释。C++语言中的多态性分为编译时的静态多态和运行时的动态多态。前者通过函数重载和运算符重载来实现,后者通过继承于虚函数实现。
静态多态
静态多态通过函数重载或运算符重载实现,其多态性在编译时已经决定了。
#include <iostream>
using namespace std;
// Cat中有函数重载,产生了静态多态。
class Cat
{
private:
char m_name[20];
int m_full = 100;
public:
Cat(const char* name)
{
strcpy_s(m_name, 20, name);
}
void play()
{
m_full--;
}
void play(int n)
{
m_full -= n;
}
void eat()
{
if (m_full >= 100)
{
cout << m_name << "我吃不下了" << endl;
return;
}
m_full++;
}
void eat(int n)
{
for(int i = 0; i < n; i++)
{
if (m_full >= 100)
{
cout << m_name << "我吃不下了" << endl;
break;
}
eat();
}
}
void show()
{
cout << m_name << " m_full: " << m_full << endl;
}
};
int main()
{
Cat cat("Tom");
cat.show();
cat.play();
cat.play(10);
cat.show();
cat.eat(15);
cat.show();
return 0;
}