C++面向对象的三大特性为:
封装
、继承
、多态
封装的意义
在设计类的时候,属性和行为写在一起,表现事物
语法:
class 类名{访问权限:属性/行为}
#include
using namespace std;
const double PI = 3.14;
class Circle {
//访问权限
public:
//属性
int m_r;//半径
//行为
//获取圆的周长
double calculateZC() {
return 2 * PI * m_r;
}
};
int main() {
//通过圆类创建具体的圆(对象)
Circle c1;
//给圆类型对象进行赋值
c1.m_r = 10;
cout << "圆的周长为:" << c1.calculateZC() << endl;
return 0;
}
设计一个学生类,属性有名字学号
#include
using namespace std;
class Student {
public:
int sid;
string name;
void showStudent() {
cout << "学号:" << sid <<",姓名:" << name << endl;
}
};
int main() {
Student s1;
s1.sid = 1;
s1.name = "张三";
s1.showStudent();
return 0;
}
#include
using namespace std;
//public: 类内和类外都可以使用
//protected:类内可以访问,类外不可以访问;子类可以访问父类中的保护权限
//private: 类内可以访问,类外不可以访问;子类不可以访问父类中的私有内容
class Person {
//公共权限
public:
string m_Name;
//保护权限
protected:
string m_Car;
//私有权限
private:
int m_PassWord;
public:
void func() {
m_Name = "张三";
m_Car = "比亚迪";
m_PassWord = 123456;
}
};
int main() {
Person p1;
p1.m_Name = "李四";
//p1.m_Car = "奔驰";//保护访问权限内容,在类外访问不到
//p1.m_PassWord = 11223344;//私有权限内容,在类外访问不到
return 0;
}
区别就在于默认的访问权限不同:
struct
默认权限是公共class
默认权限是私有在实际开发中都会将我们的成员属性私有化
示例
#include
using namespace std;
class Person {
private:
int sid;
string name;
int age;
public:
int getSid() {
return this->sid;
}
void setSid(int sid) {
this->sid = sid;
}
string getName() {
return this->name;
}
void setName(string name) {
this->name = name;
}
int getAge() {
return this->age;
}
void setAge(int age) {
this->age = age;
}
};
int main() {
Person p1;
p1.setSid(1);
p1.setName("张三");
p1.setAge(18);
cout << p1.getSid() << p1.getName() << p1.getAge() << endl;
return 0;
}
构造函数(对象的初始化状态)
语法类名(){}
在对象销毁前编译器也会调用它
语法~类名(){}
~
#include
using namespace std;
class Person {
private:
string name;
public: //注意要写作用域,目的是让类外访问
Person() {
//不写会自己给你一个空实现,写了就用你自己的
cout << "无参构造函数Person调用了" << endl; }
Person(string name) {
this->name = name;
}
};
int main() {
Person p1;
return 0;
}
注意点: 没有写构造函数的时候默认调用空实现的无参构造函数,一旦写了构造函数,之后的构造函数也不存在执行(原意:自己写了个有参构造函数自己没写无参,无参构造函数就是没有的)
#include
using namespace std;
class Person {
private:
string name;
public: //注意要写作用域,目的是让类外访问
//构造函数
Person() { cout << "无参构造函数Person调用了" << endl; }
Person(string name) {
this->name = name;
}
//析构函数
~Person() {
cout << "析构函数~Person调用了" << endl;
}
};
int main() {
Person p1; //这是在栈上的数据,main执行完后释放这个对象
return 0;
}
构造和析构都是必须要有的,如果自己不写,那么编译器会提供一个空实现的构造和析构
俩种分类方法:
class Person{
//无参构造函数
Person(){/*自行添加*/}
//有参构造函数
Person(int a){/*自行添加*/}
//拷贝构造函数
Person(const int &p){/*自行添加*/}
//析构函数
~Person(){/*自行添加*/}
};
//调用
int main(){
//1.括号法
Person p1; //无参,不需要学Person p1();有问题(这样会认为是一个函数声明)
Person p2(10); //有参
Person p3(p2);//拷贝
//2. 显示法
Person p4;//无参
Person p5 = Person(10);//有参
Person p6 = Person(p5);//拷贝
Person(10);//匿名对象,特点:当前行执行结束后,系统会立即回收掉匿名对象
//3.隐式转换法
Person p7 = 10; //相当于写了Person p7 = Person(10)
Person p8 = p7; //拷贝构造
}
注意: 不要利用拷贝构造函数初始化匿名对象,
Person(p3)
因为编译器会认为是一个对象的声明
#include
using namespace std;
class Person {
public:
int age;
public:
Person() {//无参构造
cout << "无参构造函数调用" << endl;
}
Person(int age) { //有参构造
this->age = age;
cout << "有参构造函数调用" << endl;
}
Person(const Person& p) {//拷贝构造
this->age = p.age;
cout << "拷贝构造函数调用" << endl;
}
~Person() { //析构函数
cout << "析构函数调用" << endl;
}
};
int main() {
Person p1(20);
Person p2(p1);
cout << "p2的年龄:" << p2.age << endl;//查看是否拷贝出来
return 0;
}
#include
using namespace std;
class Person {
public :
int age;
public:
Person() {//无参构造
cout << "无参构造函数调用" << endl;
}
Person(int age) { //有参构造
this->age = age;
cout << "有参构造函数调用" << endl;
}
Person(const Person& p) {//拷贝构造
this->age = p.age;
cout << "拷贝构造函数调用" << endl;
}
~Person() { //析构函数
cout << "析构函数调用" << endl;
}
};
void doWork(Person p) {
}
int main() {
Person p;
doWork(p);
return 0;
}
#include
using namespace std;
class Person {
public :
int age;
public:
Person() {//无参构造
cout << "无参构造函数调用" << endl;
}
Person(int age) { //有参构造
this->age = age;
cout << "有参构造函数调用" << endl;
}
Person(const Person& p) {//拷贝构造
this->age = p.age;
cout << "拷贝构造函数调用" << endl;
}
~Person() { //析构函数
cout << "析构函数调用" << endl;
}
};
Person doWork() {
Person p1;
cout << (int*)&p1 << endl;
return p1;
}
int main() {
Person p = doWork();
cout << (int*)&p << endl;
return 0;
}
其实应该是不一样的地址,这里编译器优化了
#include
using namespace std;
class Person {
public :
int age;
int* m_Height;
public:
Person() {//无参构造
cout << "无参构造函数调用" << endl;
}
Person(int age,int height) { //有参构造
this->age = age;
m_Height = new int(height); //指针接收堆区的数据
cout << "有参构造函数调用" << endl;
}
Person(const Person& p) {//拷贝构造
this->age = p.age;
cout << "拷贝构造函数调用" << endl;
}
~Person() { //析构函数
if (m_Height == NULL) {
delete m_Height;
m_Height = NULL;
}
cout << "析构函数调用" << endl;
}
};
int main() {
Person p1(18,160);
cout << "p1的年龄:" << p1.age << "p1身高:" << *p1.m_Height << endl;
Person p2(p1);
cout << "p2的年龄:" << p2.age << "p2身高:" << *p2.m_Height << endl;
return 0;
}
浅拷贝带来的问题,堆区资源重复释放
#include
using namespace std;
class Person {
public :
int age;
int* m_Height;
public:
Person() {//无参构造
cout << "无参构造函数调用" << endl;
}
Person(int age,int height) { //有参构造
this->age = age;
m_Height = new int(height); //指针接收堆区的数据
cout << "有参构造函数调用" << endl;
}
Person(const Person& p) {//拷贝构造
this->age = p.age;
m_Height = new int(*p.m_Height);
cout << "拷贝构造函数调用" << endl;
}
~Person() { //析构函数
if (m_Height == NULL) {
delete m_Height;
m_Height = NULL;
}
cout << "析构函数调用" << endl;
}
};
int main() {
Person p1(18,160);
cout << "p1的年龄:" << p1.age << "p1身高:" << *p1.m_Height << endl;
Person p2(p1);
cout << "p2的年龄:" << p2.age << "p2身高:" << *p2.m_Height << endl;
return 0;
}
作用: 用来初始化属性
语法:构造函数(): 属性1(值1),属性2(值2),...{}
#include
using namespace std;
class Person {
public:
int m_A;
int m_B;
int m_C;
Person():m_A(10),m_B(20),m_C(30) {}
//不是写死的
//Person(int a,int b,int c):m_A(a),m_B(b),m_C(c) {}
};
int main() {
Person p;
cout << p.m_A << endl;
}
#include
using namespace std;
class Phone {
public:
string p_name;
Phone(string p_name) :p_name(p_name) {}
};
class Person {
public:
string name;
Phone phone;
//Phone phone = phoneName;
Person(string name, string phoneName):name(name),phone(phoneName) {
}
};
int main() {
Person p("张三", "苹果XR");
cout << p.name << "拿着" << p.phone.p_name << endl;
}
#include
using namespace std;
class Person {
public:
//所有对象都共享一份
//类内声明
static int m_A;
};
//类外初始化
int Person::m_A = 100;
int main() {
Person p;
cout << p.m_A << endl;
}
静态成员不属于某个对象上,所有对象都共享一份数据
静态成员有俩种访问方式
Person p;
cout << p.m_A << endl;
//类名::静态变量名
cout << Person::m_A << endl;
静态成员变量也是有访问权限的
class 类名{
private:
static int m_B;
}
//int Person::m_B = 200;//不可以访问,原因是private私有的
#include
using namespace std;
class Person {
public:
static void func() {
cout << "static void func 调用" << endl;
}
};
int main() {
//俩种方法方式
//1.通过对象访问
Person p;
p.func();
//2.通过类名进行访问
Person::func();
}
#include
using namespace std;
class Person {
public:
static int m_A;
static void func() {
m_A = 300;//静态成员函数可以访问静态成员变量
cout << "static void func 调用" << endl;
}
};
int Person::m_A = 100;
int main() {
//俩种方法方式
//1.通过对象访问
Person p;
p.func();
//2.通过类名进行访问
Person::func();
}
非静态成员变量是通过实例来创建对象,所以静态函数不清楚非静态成员变量的变化
空对象占用内存空间为: 1。C++编译器会给每个空对象也分配一个字节空间,是为了区分空对象占内存的位置
#include
using namespace std;
class Person {
public:
int m_A; //非静态成员变量 (属于类的对象上)
static int m_B; //静态成员变量(不属于类的对象上)
void func() {} //非静态成员函数(不属于类的对象上)
static void func2() {} //静态成员函数(不属于类的对象上)
};
int Person::m_B = 0;
int main() {
Person p;
cout << sizeof(p) << endl;
}
我们知道了成员变量和成员函数是分开存储的
每一个非静态成员只会诞生一份函数实例,也就是多个同类型的对象公用一块代码
那么问题是: 这一块代码是如何区分那个对象调用自己
this指针指向被调用的成员函数所属的对象
class Person{
private:
int money;
public:
Person(int money){
this->money = money;
}
}
#include
using namespace std;
class Person {
public:
int m_Age;
void showClassName() {
cout << "this is Person class" << endl;
}
void showPersonAge() {
cout << "age = " << m_Age << endl;
}
};
int main() {
Person* p = NULL;
p->showClassName(); //正常输出
p->showPersonAge();
}
原因是this是空指针。在
m_Age
这段中,其实默认添加了this->m_Age
我们可以
class Person {
public:
int m_Age;
void showClassName() {
cout << "this is Person class" << endl;
}
void showPersonAge() {
if (this == NULL) {
return;
}
cout << "age = " << m_Age << endl;
}
};
const
后我们称这个函数为常函数mutable
后,在常函数中依然可以修改#include
using namespace std;
class Person {
public:
int m_A;
mutable int m_B; //特殊变量,即使在常函数中,也可以修改这个值
//this指针的本质 是指针常量 指针的指向是不可以修改的
void showPerson() const{ //这个const就相当于时const Person *const this;
//this->m_A = 100; //Person *const this;表达式是必须可修改的左值
//this = NULL;//this指针不能修改指针指向的
this->m_B = 100;
}
};
int main() {
Person p;
//p->showPersonAge();
}
常函数(
void showPerson const
)本质是const 对象名 *const this
。要修改就要加上mutable
关键字
const
称该对象为常对象#include
using namespace std;
class Person {
public:
int m_A;
mutable int m_B; //特殊变量,即使在常函数中,也可以修改这个值
//this指针的本质 是指针常量 指针的指向是不可以修改的
void showPerson() const{ //这个const就相当于时const Person *const this;
//this->m_A = 100; //Person *const this;表达式是必须可修改的左值
//this = NULL;//this指针不能修改指针指向的
this->m_B = 100;
}
};
int main() {
const Person p;
//p.m_A = 10;//不能修改
p.m_B = 20;//可以修改
//p->showPersonAge();
}
//常对象只能调用常函数
声明一些特殊的函数或者特殊的类来作为另一个类的朋友访问到这类的私有成员
友元关键字friend
友元的三种实现
//没有友元
#include
using namespace std;
//建筑物类
class Building {
public:
string m_SittingRoom;//客厅
private:
string m_BedRoom;//卧室
public:
Building() {
m_SittingRoom = "客厅";
m_BedRoom = "卧室";
}
};
//全局函数
void goodFriend(Building *building) {
cout << "好朋友的全局函数:" << building->m_SittingRoom << endl; //公共属性
//cout << "好朋友的自己的函数:" << building->m_BedRoom << endl; //报错
}
int main() {
Building building;
goodFriend(&building);
}
#include
using namespace std;
//建筑物类
class Building {
//goodFriend是这个Building的好朋友,可以访问Building中私有属性
friend void goodFriend(Building* building);
public:
string m_SittingRoom;//客厅
private:
string m_BedRoom;//卧室
public:
Building() {
m_SittingRoom = "客厅";
m_BedRoom = "卧室";
}
};
//全局函数
void goodFriend(Building *building) {
cout << "好朋友的全局函数:" << building->m_SittingRoom << endl; //公共属性
cout << "好朋友的自己的函数:" << building->m_BedRoom << endl;
}
int main() {
Building building;
goodFriend(&building);
}
只要写在类的最上面就可以了,不需要什么
public
核心:friend 返回值数据类型 函数名(形参);
class::名称
的说明)//class访问公共属性
#include
using namespace std;
class Building;//类声明
class GoodFriend {
public:
Building* building;
void visit(); //参观函数访问Building中的属性
GoodFriend();
};
//建筑物类
class Building {
public:
string m_SittingRoom;//客厅
private:
string m_BedRoom;//卧室
public:
Building();
};
//类外去写成员函数
Building::Building() {
m_SittingRoom = "客厅";
m_BedRoom = "卧室";
}
GoodFriend::GoodFriend() {
//创建建筑物对象
building = new Building;
}
void GoodFriend::visit() {
cout << "好朋友正在访问" << building->m_SittingRoom << endl;
}
int main() {
Building building;
GoodFriend goodFriend;
goodFriend.visit();
}
#include
using namespace std;
class Building;//类声明
class GoodFriend {
public:
Building* building;
void visit(); //参观函数访问Building中的属性
GoodFriend();
};
//建筑物类
class Building {
friend class GoodFriend; //GoodFriend是本类的好朋友,可以访问本类中私有成员(主要)
public:
string m_SittingRoom;//客厅
private:
string m_BedRoom;//卧室
public:
Building();
};
//类外去写成员函数
Building::Building() {
m_SittingRoom = "客厅";
m_BedRoom = "卧室";
}
GoodFriend::GoodFriend() {
//创建建筑物对象
building = new Building;
}
void GoodFriend::visit() {
cout << "好朋友正在访问" << building->m_SittingRoom << endl;
cout << "好朋友正在访问" << building->m_BedRoom << endl;
}
int main() {
Building building;
GoodFriend goodFriend;
goodFriend.visit();
}
核心:
friend class 类名
这里提到的一个写法知识点
class 类名{
public:
数据类型 成员变量名;
类名();
返回值数据类型 成员函数名();
}
//初始化(构造函数)
类名::类名(){/*初始化*/}
//初始化(成员函数)
返回值数据类型 类名::成员函数(/*形参*/){/*内容*/}
class 类名1{
void 成员函数();
}
class 类名2{
friend 类名1::成员函数(); //类1下的成员函数作为本类的好朋友,可以访问私有成员
private:
int test;
}
//通过成员函数重载+运算符
#include
using namespace std;
class Person {
public:
int m_A;
int m_B;
Person operator+(Person &p) {
Person temp;
temp.m_A = this->m_A + p.m_A;
temp.m_B = this->m_B + p.m_B;
return temp;
}
};
int main() {
Person p1;
p1.m_A = 10;
p1.m_B = 10;
Person p2;
p2.m_A = 20;
p2.m_B = 20;
Person p3 = p1 + p2;
cout << "p2.m_A = " << p3.m_A << endl;
cout << "p2.m_B = " << p3.m_B << endl;
}
成员函数的本质:
Person p3 = p1.operator+(p1);
全局函数重载本质调用:Person p3 = operator+(p1,p2)
ostream operator<<(ostream &cout,对象数据类型 &名字){
cout << "自定义" <<"自定义";
}
ostream &operator<<(ostream &cout,对象数据类型 &名字);
void operator++(){
//先做运算
//再返回
return ...;
}
c++编译器至少给一个类添加4个函数
operator=
对属性进行值拷贝void operator=(){
if(m_Age != NULL){
delete m_Age;
m_Age = NULL;
}
}
void operator==(){}
void operator!=(){}
//仿函数没有固定的写法
void operator()(string test){
cout << test <<endl;
}
int operator()(string test,int age){}
语法
class 子类: 继承方式 父类
class A{
//父类
public:
int m_A;
protected:
int m_B;
private:
int m_C;
};
class B:public A{
void func(){
m_A = 10;//父类中的公共权限成员到子类依旧是公共权限
m_B = 10;//父类中的保护权限成员到子类依旧是保护权限
//m_C = 10;//父类中的隐私权限成员到子类中是拿不到私有权限
}
};
class A{
//父类
public:
int m_A;
protected:
int m_B;
private:
int m_C;
};
class B:protected A{
public:
void func(){
m_A = 10;//父类中的公共权限成员到子类中变为了保护权限
m_B = 10;//父类中的保护权限成员到子类依旧是保护权限
//m_C = 10;//父类中的隐私权限成员到子类中是拿不到私有权限
}
};
class A{
//父类
public:
int m_A;
protected:
int m_B;
private:
int m_C;
};
class B:private A{
public:
void func(){
m_A = 10;//父类中的公共权限成员到子类中变为了私有成员
m_B = 10;//父类中的保护权限成员到子类中变为了私有成员
//m_C = 10;//父类中的隐私权限成员到子类中是拿不到私有权限
}
};
class A{
//父类
public:
int m_A;
protected:
int m_B;
private:
int m_C;
};
class B:public A{
public:
int m_D;
};
void test(){
cout << "sizeof B=" << sizeof(B) << endl;
}
父类中非静态是私有还是公共权限的数据我们子类都会被继承下来保留一份(自己中的属性也包括)
验证:打开图中高亮的文件
注意: 文件路径不能有
&
#cl /d1 报告单个类的布局(reportSingleClassLayout类名) 类在的.cpp文件
cl /d1 reportSingleClassLayoutB main.cpp
#include
using namespace std;
class A {
//父类
public:
int m_A;
A() {
cout << "父类A构造函数" << endl;
}
~A() {
cout << "父类A析构函数" << endl;
}
protected:
int m_B;
private:
int m_C;
};
class B :public A {
public:
int m_D;
B() {
cout << "子类B构造函数" << endl;
}
~B() {
cout << "子类B析构函数" << endl;
}
};
void test() {
cout << "sizeof B=" << sizeof(B) << endl;
}
int main() {
B b;
return 0;
}
问题: 父类和子类出现了同样名称的成员
#include
using namespace std;
class A {
//父类
public:
int m_A;
A() {
m_A = 100;
cout << "父类A构造函数" << endl;
}
};
class B :public A {
public:
int m_A;
B() {
m_A = 200;
cout << "子类B构造函数" << endl;
}
void func(){}
};
void test() {
B b;
cout << "B类下的m_A=" << b.m_A << endl;
}
int main() {
test();
return 0;
}
//子类实例对象名.父类名::同名成员变量/同名成员函数
void test() {
B b;
cout << "A类下的m_A=" << b.A::m_A << endl;
}
如果想访问到父类中被隐藏的成员函数,需要加作用域
子类实例名.类名::函数名(/*形参*/);
#include
using namespace std;
class Base {
public:
static int m_A;
static void func() {
cout << "Base func" << endl;
}
};
int Base::m_A = 100;
class Son:public Base{
public:
static int m_A;
static void func() {
cout << "Son func" << endl;
}
};
int Son::m_A = 200;
int main() {
//同名静态成员属性
Son s;
//1.通过对象的方式访问
cout << "通过对象的方式访问" << endl;
cout << "子类s的静态变量=" << s.m_A << endl;
cout << "父类Base下的静态变量=" << s.Base::m_A << endl;
//2.通过类名的方式访问
cout << "通过类名的方式访问" << endl;
cout << "子类s的静态变量=" << Son::m_A << endl;
cout << "父类Base下的静态变量=" << Son::Base::m_A << endl;
//同名静态成员函数
cout << "通过对象的方式访问" << endl;
s.func();
s.Base::func();
cout << "通过类名的方式访问" << endl;
Son::func();
Son::Base::func();
return 0;
}
在C++中可以继承多个类
语法:class 子类:继承方式 父类1,继承方式 父类2...
因为可能存在俩个父类中存在成员重名问题,所以实际开发中不建议使用多继承
#include
using namespace std;
class Base1 {
public:
int m_A;
int m_D;
Base1() {
m_A = 100;
}
};
class Base2 {
public:
int m_B;
int m_D;
Base2() {
m_B = 200;
}
};
class Son :public Base1, public Base2 {
public:
int m_C;
};
int main() {
Son s;
cout << "sizeof Son=" << sizeof(s) << endl;
cout << "Base1 m_D=" << s.Base1::m_D << endl;
cout << "Base2 m_D=" << s.Base2::m_D << endl;
return 0;
}
俩个派生类继承一个基类(人话:俩个子类一个父类);之后一个类继承了这俩个派生类
#include
using namespace std;
class Anime {
public:
int m_Age;
};
class Sheep :public Anime {
};
class Tuo :public Anime {
};
class SheepTuo :public Sheep, public Tuo {};
int main() {
SheepTuo st;
st.Sheep::m_Age = 18;
st.Tuo::m_Age = 20;
//当出现菱形继承,俩个父类拥有相同的数据,需要加以作用域区分
cout << "st.Sheep::m_Age = " << st.Sheep::m_Age << endl;
cout << "st.Tuo::m_Age = " << st.Tuo::m_Age << endl;
return 0;
}
解决: 继承之前加上关键字
virtual
变成虚继承
#include
using namespace std;
class Anime {
public:
int m_Age;
};
class Sheep :virtual public Anime {
};
class Tuo :virtual public Anime {
};
class SheepTuo :public Sheep, public Tuo {};
int main() {
SheepTuo st;
st.Sheep::m_Age = 18;
st.Tuo::m_Age = 20;
//当出现菱形继承,俩个父类拥有相同的数据,需要加以作用域区分
cout << "st.Sheep::m_Age = " << st.Sheep::m_Age << endl;
cout << "st.Tuo::m_Age = " << st.Tuo::m_Age << endl;
return 0;
}
#include
using namespace std;
class Anime {
public:
void speak() {
cout << "动物在说话" << endl;
}
};
class Cat :public Anime {
public:
void speak() {
cout << "猫在说话" << endl;
}
};
//执行说话函数
void doSpeak(Anime& anime) { //父类的引用指向子类对象Anime &anime = cat
anime.speak();
}
int main() {
Cat cat;
doSpeak(cat);
return 0;
}
输出的结果是
动物在说话
,这个时候就要使用虚函数
了
class Anime {
public:
//虚函数
virtual void speak() {
cout << "动物在说话" << endl;
}
};
//动态多态的满足条件
//1.有继承关系
//2.子类要重写父类的虚函数
动态多态使用
多态的优点
class AbstractCalculator{
public:
virtual int getResult(){
return 0;
}
int num1;
int num2;
};
//加法计算器类
class AddCalulator:public AbstractCalculator{
public:
int getResult(){
return num1+num2;
}
};
//乘法计算器类
class MulCalulator:public AbstractCalculator{
public:
int getResult(){
return num1 * num2;
}
};
int main(){
AbstractCalculator *add = new AddCalulator();
add->num1 = 10;
add->num2 = 20;
}
以案例1来看
AbstractCalculator
中的虚函数getResult
的return 0
一直都没使用过,所以我们可以改为纯虚函数
语法:virtual 返回值类型 函数名(参数列表) = 0;
当类中有了纯虚函数,这个类也被称为抽象类
#include
using namespace std;
//Base是抽象类
class Base {
public:
//只要有一个纯虚函数,这个类就是抽象类
//抽象类无法实例化对象
virtual void func() = 0;
};
class Son :public Base {
public:
void func() {
cout << "Son func" << endl;
}
};
int main() {
Base* base = new Son;
base->func();
return 0;
}