多态性是面向对象编程中的一个核心概念,它允许对象通过统一的接口表现出不同的行为。多态性增强了程序的灵活性和可扩展性。
编译时多态,也称为静态多态或早绑定(early binding),是在编译阶段确定调用哪个函数或方法。这主要通过函数重载和模板来实现。
运行时多态,也称为动态绑定(dynamic binding)或晚绑定(late binding),是在运行时确定调用哪个函数或方法。这主要通过继承和虚函数来实现。
virtual
的成员函数。当通过基类指针或引用调用虚函数时,如果指针或引用实际上指向的是派生类对象,那么将调用派生类中重写的虚函数版本。这种机制允许在运行时根据对象的实际类型来确定调用哪个版本的函数。
多态需要继承关系,在继承关系下调用同一函数产生不同行为。
class A
{
public:
virtual void P(int a = 0)
{
cout << a << "A" << endl;
}
};
class B :public A
{
public:
virtual void P(int a = 1)
{
cout << a <<"B" << endl;
}
};
void C(A* it)
{
it->P();
}
int main()
{
A a;
B b;
C(&a);
C(&b);
return 0;
}
如上文给出的对A的virtual void P()是虚函数而且完成了覆写
虚函数就是在类成员函数前加virtua修饰(非成员函数不可以加virtual)
class A
{
public:
virtual void P(int a = 0)
{
cout << a << "A" << endl;
}
};
class B :public A
{
public:
virtual void P(int a = 1)
{
cout << a <<"B" << endl;
}
};
虚函数的覆写需要满足
但是注意
还有就是 派生类没有virtual不影响派生类的虚函数,但是基类必须有
class A
{
public:
virtual void P(int a = 0)
{
cout << a << "A" << endl;
}
};
class B :public A
{
public:
void P(int a = 1)//这里打印出来的a是0 如果按照多态来调用
{
cout << a << "B" << endl;
}
};
就是派生类与基类的虚函数在写的时候各自返回对自己的指针或者引用
class A
{
public:
virtual A& P(int a = 0)
{
cout << a << "A" << endl;
return *this;
}
virtual A* G(int a = 0)
{
cout << a << "A" << endl;
return this;
}
};
class B :public A
{
public:
virtual B& P(int a = 1)
{
cout << a << "B" << endl;
return *this;
}
virtual B* G(int a = 1)
{
cout << a << "B" << endl;
return this;
}
};
基类的析构函数为虚函数,此时派生类析构函数只要定义,无论是否有virtual关键字,都构成了与基类的析构函数的重写
class A
{
public:
~A()//这里不构成虚函数 如果以A*调用只会清除掉A内的玩意,B申请的玩意会清理不完全
{
}
};
class B :public A
{
public:
~B()
{
}
private:
string* T;
};
对于A
class A
{
public:
virtual ~A()
{
}
};
override是用来检测是否构成了虚函数的重写 final是拒接重写虚函数
class A
{
public:
virtual void P(int a = 0)
{
cout << a << "A" << endl;
}
virtual void L() final {}
};
class B :public A
{
public:
virtual void P(int a = 1) override
{
cout << a <<"B" << endl;
}
};
重载/重写/隐藏特性
定义: 重载是指在同一个作用域内,允许存在多个同名但参数列表不同的函数或运算符。这些重载的函数或运算符通过参数列表的不同来区分。
特点:
定义: 重写(覆盖)是指在派生类中重新定义基类中的虚函数。这意味着当通过基类指针或引用来调用虚函数时,如果指针或引用实际上指向的是派生类对象,那么将调用派生类中重写的虚函数版本。
特点:
virtual
关键字声明)。override
关键字来显式指定重写基类虚函数,这有助于编译器检查重写是否正确。定义: 隐藏是指派生类中的函数或成员变量隐藏了基类中的同名函数或成员变量。当通过派生类对象或派生类指针来访问这些被隐藏的成员时,将访问派生类中的版本,而不是基类中的版本。
特点:
class A//无法实例化
{
public:
virtual void T() = 0 {cout << "我是抽象类" << endl;}//无法调用
};
class B :public A
{
public:
virtual void T() { cout << "我不是抽象类"<<endl;}
};
int main()
{
B b;
b.T();
return 0;
}
虚函数表
虚函数表指针
_vfptr
)。这个虚函数表的位置在每个类里面的成员变量里,而且是先完全继承基类的,然后再修改复写的,也就是没有覆写的和基类的指向同一个函数地址,覆写的则指向自己的函数地址
虚数数表指针也占空间,大小是指针的大小
class A
{
public:
virtual void T(){}
int _a;
};
class B:public A
{
public:
virtual void T() { cout << "我覆写啦"; }
int _b;
char _c;
};
int main()
{
cout << sizeof(A) << ' ' << sizeof(B) << endl;
return 0;
}
这个_vfptr是可以被看到的
多态的原理
多态是通过,根据你提供的ptr判断执行的
特殊:
class A
{
public:
virtual void T(){}
virtual void G(){}//这个没有覆写
int _a;
};
class B:public A
{
public:
virtual void T() { cout << "我覆写啦"; }
virtual void L() {}//这没有前置的函数
int _b;
char _c;
};