c++的三大特性
c++有三大特性:封装、继承和多态。
首先,我们谈谈c++的封装,在学习c语言的时候我们都知道,在c语言中我们可以使用struct结构体来将数据存放起来,上节我们说到c语言的一切语法适用于c++,所以c++自然也可以用同样的方法存放数据,如下:
#include <iostream> using namespace std; struct S{ int a, b; }; void f(const S& s){ //以引用的方式传递地址 cout << s.a << " " << s.b << " "; } int main(){ S s = {1, 2}; //定义一个S类,并赋值 f(s); //通过向函数f传递s的地址,以输出s中的两个属性 S* z = &s; //定义一个指向s的指针z z->a = 3; //通过指针间接改变s中属性e1的值,注意,针对指针必须使用“->”符号,用来调用结构体中的成员 (*z).b = 4; //通过指针指向的地址直接改变s中的属性e2的值,这里则要用"."调用,因为此处是*z f(s); //再次输出 }
但是在这样的结构体中的数据会存在被函数调用或修改造成数据泄露的情况,所以在c++中提供了一些关键词来保护数据的访问权限--public、private、pretected。
public(共有):在这一关键词之后的数据(属性或方法)均为公共的,在结构体外的任何函数都可对其访问或修改
private(私有):在这一关键词之后的数据(属性或者方法)均为对象私有的,只能在结构体内部进行修改或访问,其他函数或结构体没有访问权限。
pretected(保护的):在这一关键词之后的数据均为受保护的类型,只有在该类或由该类派生出来的类中才有访问权限。例如:
#include <iostream> #include <cmath> #include <iomanip> using namespace std; struct Complex{ private: //关键词private修饰,表示下面的re和im为结构体Complex的私有成员,只能在结构体中被访问或修改 double re; double im; public: //关键词private修饰,表示下面的方法(value,amount,getReal,getImag)为公共成员,不仅能在能在结构体中被访问或修改,也可在main函数中被调用 void value(double r, double i){ re = r; im = i; } double amount(){ return sqrt(re * re + im * im); } double getReal(){ return re; } double getImag(){ return im; } }; int main(){ Complex z; z.re = 3; //产生编译错误 z.im = 4; //产生编译错误,此处re和im为结构体Complex的私有成员,在main函数中无访问和修改权限 z.value(3, 4); //此处合法,方法value在结构体Complex,其拥有访问和修改im和re的权限,而value被关键词public所修饰,在main函数中可以访问或调用 cout << z.re << " + " << z.im << "j"; //产生编译错误 cout << z.getReal() << " + " << z.getImag() << "j"; //合法 cout << endl; cout << "the amount of this complex number is: " << sqrt(z.re * z.re + z.im * z.im); //产生编译错误 cout << "the amount of this complex number is: " << z.amount(); //合法
除了struct,c++还提供了一个名叫类的关键词(class),在class中,所有的属性和方法,如果没有特别声明,则均视为private。
接下来我们说说c++的继承,继承是面向对象程序设计中使代码可以复用的重要手段,它允许程序员在原有类特性的基础上进行扩展增加功能。这样产生的新的类叫派生类。
在c++中继承的格式为:派生类名字 : 继承权限 父类名字,不同的继承方式有不同的继承权限,
在C++语言中,一个派生类可以从一个基类派生,也可以从多个基类派生。从一个基类派生的继承称为单继承;从多个基类派生的继承称为多继承。派生类一般可以拥有基类的所有变量和函数(除了构造函数和析构函数的成员),并且可以在派生类中重写基类的方法和变量,当然这会受到继承权限的影响。并且派生类可以拥有基类没有的方法与变量,可以说派生类是一种特殊的基类。以下便是继承方式对子类对外访问属性影响的代码
#include <cstdlib> #include <iostream> using namespace std; class A { private: int a; protected: int b; public: int c; A() { a = 0; b = 0; c = 0; } void set(int a, int b, int c) { this->a = a; this->b = b; this->c = c; } }; class B : public A { public: void print() { //cout<<"a = "<<a; //err cout<<"b = "<<b; cout<<"c = "<<endl; } }; class C : protected A { public: void print() { //cout<<"a = "<<a; //err cout<<"b = "<<b; cout<<"c = "<<endl; } }; class D : private A { public: void print() { //cout<<"a = "<<a; //err cout<<"b = "<<b<<endl; cout<<"c = "<<c<<endl; } }; int main_01(int argc, char *argv[]) { A aa; B bb; C cc; D dd; aa.c = 100; //ok bb.c = 100; //ok //cc.c = 100; //err 类的外部是什么含义 //dd.c = 100; //err aa.set(1, 2, 3); bb.set(10, 20, 30); //cc.set(40, 50, 60); //ee //dd.set(70, 80, 90); //ee bb.print(); cc.print(); dd.print(); system("pause"); return 0; }
继承就简单说到这里,最后我们谈谈c++的多态性,实现c++多态的关键在于虚函数,即在函数声明的前面加上virtual关键字,在派生类中重写该函数,运行时将会根据对象的实际类型来调用相应的函数。如果对象类型是派生类,就调用派生类的函数;如果对象类型是基类,就调用基类的函数。
1:用virtual关键字申明的函数叫做虚函数,虚函数肯定是类的成员函数。
2:存在虚函数的类都有一个一维的虚函数表叫做虚表,类的对象有一个指向虚表开始的虚指针。虚表是和类对应的,虚表指针是和对象对应的。
3:多态性是一个接口多种实现,是面向对象的核心,分为类的多态性和函数的多态性。
4:多态用虚函数来实现,结合动态绑定.
5:纯虚函数是虚函数再加上 = 0;
6:抽象类是指包括至少一个纯虚函数的类。
纯虚函数:virtual void fun()=0;即抽象类!必须在子类实现这个函数,即先有名称,没有内容,在派生类实现内容。下面就是使用虚函数与非虚函数的对比
class Base { public: virtual void Funtest1(int i) { cout << "Base::Funtest1()" << endl; } void Funtest2(int i) { cout << "Base::Funtest2()" << endl; } }; class Drived :public Base { virtual void Funtest1(int i) { cout << "Drived::Fubtest1()" << endl; } virtual void Funtest2(int i) { cout << "Drived::Fubtest2()" << endl; } void Funtest2(int i) { cout << "Drived::Fubtest2()" << endl; } }; void TestVirtual(Base& b) { b.Funtest1(1); b.Funtest2(2); } int main() { Base b; Drived d; TestVirtual(b); TestVirtual(d); return 0; }
而这个程序运行的结果为
在调用FuncTest2的时候我们看出来他并没有给我们调用派生类的函数,因此我们可以得到动态多态的条件为基类中必须包含虚函数并且派生类中一定要对基类中的虚函数进行重写,通过基类对象的指针或者引用调用虚函数。
好了今天的c++特性就介绍到这里!