目录
- 前言
- 011虚函数_使用基类指针实现覆盖特性
- 012虚函数_使用引用实现覆盖特性
- 013使用多态场景小例程
- 020构成多态的条件
- 030虚析构函数
- 040纯虚函数
- 051typeinfo运算符_获取类型信息
- 052typeinfo_根据不同类型进行不同操作
前言
本笔记所涉及到的编程环境与 《C++ · 代码笔记1 · 从C到C++》 中的编程环境一致,具体可参考此笔记。
011虚函数_使用基类指针实现覆盖特性
相关代码:
#include <iostream>
using namespace std;
class Base
{
public:
virtual void show()
{
cout << "Base show" << endl;
}
};
class Derived : public Base
{
public:
// 使用 override 关键字明确表示覆盖
void show() override
{
cout << "Derived show" << endl;
}
};
int main()
{
// 基类指针调用基类函数
Base *bPtr = new Base;
bPtr->show();
// 派生类指针调用派生类函数
Derived *dPtr = new Derived();
dPtr->show();
// 基类指针指向派生类对象,基类show函数已经被声明为了虚函数,此时会表现出多态性。
// 当基类相关函数声明为虚函数时,派生类相关函数将会覆盖基类相关函数,
// 此时会根据基类指针指向的对象类型调用相关函数
bPtr = dPtr;
bPtr->show();
return 0;
}
运行结果:
012虚函数_使用引用实现覆盖特性
相关代码:
#include <iostream>
using namespace std;
class Base
{
public:
virtual void show()
{
cout << "Base show" << endl;
}
};
class Derived : public Base
{
public:
// 使用 override 关键字明确表示覆盖
void show() override
{
cout << "Derived show" << endl;
}
};
int main(int argc, char const *argv[])
{
Base b_obj;
Base &br = b_obj;
br.show();
Derived d_obj;
Derived &dr = d_obj;
dr.show();
// 基类引用派生类对象,此时由于基类的函数被声明为了虚函数,表现出了多态性,
// 所以此时调用的是派生类的函数
Base &brd = d_obj;
brd.show();
return 0;
}
运行结果:
013使用多态场景小例程
相关代码:
#include <iostream>
using namespace std;
/**
* 这个例子中就体现出了多态的优点,如果使用非多态的方式实现这个程序,
* 那么将会需要定义很多指针,但使用了多态仅使用一个指针变量即可。
*/
// 动物类
class Animal
{
public:
virtual void makeSound() const
{
cout << "动物发出声音!" << endl;
}
virtual ~Animal() {}
};
// 狗类
class Dog : public Animal
{
public:
void makeSound() const override
{
cout << "--狗狗:汪汪!" << endl;
}
};
// 猫类
class Cat : public Animal
{
public:
void makeSound() const override
{
cout << "--猫咪:喵喵!" << endl;
}
};
// 鸟类
class Bird : public Animal
{
public:
void makeSound() const override
{
cout << "--小鸟:啾啾!" << endl;
}
};
// 大象类
class Elephant : public Animal
{
public:
void makeSound() const override
{
cout << "--大象:哞哞!" << endl;
}
};
int main()
{
Animal *p = new Animal;
p->makeSound();
// 创建不同类型的动物
p = new Dog;
p->makeSound();
p = new Cat;
p->makeSound();
p = new Bird;
p->makeSound();
p = new Elephant;
p->makeSound();
// 释放内存
delete p;
return 0;
}
运行结果:
020构成多态的条件
相关代码:
#include <iostream>
using namespace std;
/**
* 构成多态条件:
* 1、必须存在继承关系;
* 2、继承关系中必须有同名的虚函数,并且它们是覆盖关系(函数原型相同)。
* 3、存在基类的指针,通过该指针调用虚函数。
*/
class Base
{
public:
virtual void func();
virtual void func(int);
void func(double);
};
void Base::func()
{
cout << "void Base::func()" << endl;
}
void Base::func(int n)
{
cout << "void Base::func(int)" << endl;
}
void Base::func(double n)
{
cout << "void Base::func(double)" << endl;
}
class Derived : public Base
{
public:
void func();
void func(char *);
void func(double);
};
void Derived::func()
{
cout << "void Derived::func()" << endl;
}
void Derived::func(char *str)
{
cout << "void Derived::func(char *)" << endl;
}
void Derived::func(double n)
{
cout << "void Derived::func(double)" << endl;
}
/** 本例是一个简单的多态例程。以本例来说,当一个基类指针指向派生类对象时,
* 会调用的函数有以下三种情况:
* 1、派生类【重写】了基类的虚函数,在调用处传递完全符合【重写】函数的形参列表参数时,
* 调用派生类重写的函数,如下面的 a 注释处的代码
* 2、派生类【未重写】基类的虚函数,在调用处传递完全符合【未重写】函数的形参列表参数时,
* 调用基类的虚函数,如下面的b注释处的代码
* 3、仅派生类有该函数,基类没有相关的虚函数,则不能调用,否则会编译报错,
* 如下面c注释处的代码
* 4、补充内容:当基类成员函数未声明为虚函数,即使是派生类对其进行了隐藏,
* 但调用的仍会是基类的函数,如注释d处代码所示。
**/
int main(int argc, char const *argv[])
{
Base *p = new Derived();
// a、调用的是派生类的虚函数,构成了多态。
p->func();
// b、调用的是基类的虚函数,因为派生类中没有函数覆盖它。
p->func(10);
// c、编译报错,因为通过基类的指针只能访问从基类继承过去的成员,不能访问派生类新增的成员。
// p->func("test");
// p指针是基类指针且基类函数未被声明为virtual,这将会调用基类成员函数
p->func(1.0);
return 0;
}
运行结果:
030虚析构函数
相关代码:
#include <iostream>
/**
* 基类的析构函数如果不声明为虚析构函数,那么当基类指针指向派生类对象的情况下
* 销毁对象仅调用基类的析构函数,不会调用派生类的析构函数,
* 这会导致派生类中的资源无法得到释放,产生内存泄漏的危险
**/
class Base
{
public:
Base()
{
std::cout << "基类构造函数被调用" << std::endl;
}
virtual ~Base()
{
std::cout << "基类析构函数被调用" << std::endl;
}
};
class Derived : public Base
{
public:
Derived()
{
std::cout << "派生类构造函数被调用" << std::endl;
}
~Derived() override
{
std::cout << "派生类析构函数被调用" << std::endl;
}
};
int main()
{
Base *obj = new Derived();
delete obj;
return 0;
}
运行结果:
040纯虚函数
相关代码:
#include <iostream>
/**
* 1、仅能在类中定义纯虚函数
* 2、纯虚函数必须要在派生类中定义,且全部完成实现
*/
class A
{
public:
// 定义纯虚函数vFunc1,没有函数体,需要在派生类中实现
virtual void vFunc1(void) = 0;
// 定义纯虚函数vFunc2,没有函数体,需要在派生类中实现
virtual void vFunc2(void) = 0;
};
class B : public A
{
public:
// 声明B类对A类的vFunc1函数进行覆盖实现
void vFunc1(void) override;
};
// B类对A类的vFunc1函数的具体实现
void B::vFunc1(void)
{
std::cout << "派生类 B类 实现了 抽象基类的vFunc1函数" << std::endl;
}
class C : public B
{
public:
// 声明C类对A类的vFunc2函数进行覆盖实现
void vFunc2(void) override;
};
// C类对A类的vFunc2函数的具体实现
void C::vFunc2(void)
{
std::cout << "派生类 C类 实现了 抽象基类的vFunc2函数" << std::endl;
}
int main(int argc, char const *argv[])
{
C c_obj;
A *pa = &c_obj;
// 通过基类指针调用派生类实现的vFunc1函数
pa->vFunc1();
// 通过基类指针调用派生类实现的vFunc2函数
pa->vFunc2();
return 0;
}
运行结果:
051typeinfo运算符_获取类型信息
相关代码:
#include <iostream>
#include <typeinfo>
// 定义一个简单的类
class MyClass
{
public:
MyClass() {}
};
// 定义一个简单的结构体
struct MyStruct
{
int member;
};
int main()
{
int i = 10;
double d = 10.5;
char c = 'a';
std::string s = "Hello";
MyClass obj;
struct MyStruct struct_obj;
// 获取和打印不同类型的类型信息
std::cout << "typeid(1).name(): " << typeid(1).name() << std::endl;
std::cout << "typeid(1.0).name(): " << typeid(1.0).name() << std::endl;
std::cout << "typeid(int).name(): " << typeid(i).name() << std::endl;
std::cout << "typeid(double).name(): " << typeid(d).name() << std::endl;
std::cout << "typeid(char).name(): " << typeid(c).name() << std::endl;
std::cout << "typeid(std::string).name(): " << typeid(s).name() << std::endl;
std::cout << "typeid(MyClass).name(): " << typeid(obj).name() << std::endl;
std::cout << "typeid(MyStruct).name(): " << typeid(struct_obj).name() << std::endl;
// 比较两个类型是否相同
if (typeid(obj) == typeid(MyClass))
{
std::cout << "obj is of type MyClass" << std::endl;
}
if (typeid(struct_obj) == typeid(MyStruct))
{
std::cout << "struct_obj is of type MyStruct" << std::endl;
}
return 0;
}
运行结果:
052typeinfo_根据不同类型进行不同操作
相关代码:
#include <iostream>
#include <typeinfo>
using namespace std;
// 基类
class Animal
{
public:
virtual void speak() const
{
cout << "我是一只动物。" << endl;
}
virtual ~Animal(){}; // 将析构函数声明为虚的
};
// 派生类
class Dog : public Animal
{
public:
void speak() const override
{
cout << "我是一只狗。汪汪!" << endl;
}
~Dog() {}
};
// 另一个派生类
class Cat : public Animal
{
public:
void speak() const override
{
cout << "我是一只猫。喵喵!" << endl;
}
~Cat() {}
};
int main(int argc, char const *argv[])
{
Animal *animal;
int choice;
cout << "输入一个数字(1 表示狗,2 表示猫): ";
cin >> choice;
if (choice == 1)
{
animal = new Dog();
}
else if (choice == 2)
{
animal = new Cat();
}
else
{
animal = new Animal();
}
// 使用 typeid 进行类型检查
if (typeid(*animal) == typeid(Dog))
{
cout << "这只动物是一只狗。" << endl;
}
else if (typeid(*animal) == typeid(Cat))
{
cout << "这只动物是一只猫。" << endl;
}
else
{
cout << "这只动物是一只普通的动物。" << endl;
}
// 清理动态分配的内存
delete animal;
return 0;
}
运行结果: