C++基础(3)
C++是面向对象的编程语言
C++是面向对象的语言,对于面向对象的语言,都是具有封装 继承和多态这几个特点的。
面向对象
C++中使用class
来对某些具备相同特性的事物进行大致概述,比如人类,共同的属性有手,脚,脸部,头发等,在我们构建一个类的时候,这些属性就是这个类的属性,一些人类的行为就可以作为人类的方法。虽然有了这些属性和方法,但是类依旧是一个很抽象的存在。那么,在我们使用时,就需要把类实例化,也就是创建类对象。犹如女娲造人,造出来的人都是有自己的名字,样貌,性格等。
封装
对于类的属性,我们是很有必要设置它们的属性的,在C语言中,我们会用结构体struct
来定义一个有多种类型组成的新类型,这应该就类的前身吧。一般的用法就是通过.
或->
获取里面的属性,这是因为struct
里面的属性默认是公开的(public
)。
在C++的class
中,属性默认是私有的(private
)。类对象是不能直接访问类的私有成员属性的,打个比方,我们的名字一样,就应该设置为private
,否则我们没事就去改一下,会出大问题的hh
#include <iostream>
#include <string>
using namespace std;
class Human{
public:
Human(string name, int age, double height)
: _name(name), _age(age), _height(height)
{
}
void say_hello() {
cout << "my name is " << _name << " and age:" << _age << endl;
}
private:
string _name;
int _age;
double _height;
};
int main() {
Human h1("Busy", 21, 171.6); // 使用构造函数构造对象
h1.say_hello();
return 0;
}
输出结果:
my name is Busy and age:21
继承
C++的继承,通俗的来说就是子承父业,子类是拥有父类的全部属性和方法的,这样在开发过程中,就能避免多个类的某些方法属性是重复的,少些很多重复的代码,可以提高效率。C++中是支持多重继承的,即一个类可以继承多个类作为父类。
#include <iostream>
#include <string>
using namespace std;
// 定义父类
class Base {
public:
Base(int num)
: _num(num) {
}
void print() {
cout << "my number is " << _num << endl;
}
private:
int _num;
};
// 子类, 继承于Base父类
class Child : public Base {
public:
Child(int num) : Base(num) // 子类继承了父类的属性,同时也继承了父类的方法,包括构造方法
{
}
};
int main() {
// 创建Base类对象,创建时使用构造函数创建
Base base(1);
// 调用print方法
base.print();
// 创建一个子类对象,创建时使用构造函数创建
Child child(20);
child.print();
return 0;
}
输出结果:
my number is 1
my number is 20
多态
多态的实现有两种方式,一种是动态实现(通过虚函数实现),另一种是静态实现多态(通过模板或函数重载实现),这里先描述类的多态实现。
动态多态是指在程序运行阶段,通过判断父类指针的指向来确定应该调用哪一个同名函数(子类会重写父类定义或声明的 virtual
修饰的虚函数),从而满足程序的需要。
#include <iostream>
using namespace std;
class A {
public:
virtual void func() {
cout << "this is class A func()" << endl;
}
};
class B : public A {
public:
virtual void func() {
cout << "this is class B func()" << endl;
}
};
class C : public A {
public:
virtual void func() {
cout << "this is class C func()" << endl;
}
};
int main() {
// 定义三个类对象,分别是A、B、C类的对象
A a;
B b;
C c;
// 一个父类指针
// 父类指针指向分别指向三个类时调用func函数
A *parent = &a;
parent->func(); // 指向A
parent = &b; // 指向B
parent->func();
parent = &c; // 指向C
parent->func();
return 0;
}
输出结果:
this is class A func()
this is class B func()
this is class C func()
那么动态多态是怎么使用虚函数来实现的呢?其实在父类把一个函数声明为虚函数时,这个类会维护一个虚函数表,在编译过程中只是把每一个虚函数方法这个虚函数表里面,在运行时通过父类指针的指向确定是需要调用哪一个类的虚函数,再到虚函数表里面找到该函数,然后调用。
// 证明是维护了一个虚函数表, 空类的字节大小为1,类的函数是不占类内存的
class E{
public:
void print() {
cout << "this is a empty class" << endl;
}
};
class V{
public:
virtual void print() {
cout << "this class has a virtual function" << endl;
}
};
int main() {
cout << "empty class size : " << sizeof(E) << endl;
cout << "has virtual function class size : " << sizeof(V) << endl;
return 0;
}
输出结果:
empty class size : 1
has virtual function class size : 8 // 这里是8,因为我用的64位系统
总结
- 封装使类的一些属性和方法更加安全,让使用者不必考虑实现,调用接口即可。
- 继承能使某一部分具有相同属性或方法的类相关联,对于一些共性,可以统一化,对于特性也能自由发展。
- 多态的使用可以让一个方法在不同指向时能展现不一样的效果。