C++:类和对象
一、类和对象的定义
C++ 在 C 语言的基础上增加了面向对象编程,C++ 支持面向对象程序设计。类是 C++
的核心特性,通常被称为用户定义的类型。类用于指定对象的形式,它包含了数据表示法和用
于处理数据的方法。类中的数据和方法称为类的成员。函数在一个类中被称为类的成员。
打个比方说明一下什么是类,比如有一条小狗,小狗有名字叫旺财,旺财的年龄是 2 岁,
同时旺财会汪汪的叫,也能跑。我们统称狗这个为类,类是我们抽象出来的,因为狗不只有上
面的属性,还有体重,毛发的颜色等等,我们只抽象出几种属性成一个类。具体到哪条狗就叫
对象。
从类中实例化对象分两种方法,一种是从栈中实例化对象,一种是从堆中实例化对象。
类是创建对象的模板,一个类可以创建多个对象,每个对象都是类类型的一个变量;创建对象的过程也叫做类的实例化。
类的定义
class 类名{
public:
公有的数据;
protected:
保护的数据;
private:
私有的数据;};
C++通过 public、protected、private 三个关键字来控制成员变量和成员函数的访问权限,它们分别表示公有的、受保护的、私有的,被称为成员访问限定符。所谓访问权限,就是你能不能使用该类中的成员。
#include <iostream>using namespace std;class Dog
{public://不写关键字的时候默认是private属性string name;int age;void run(){cout<<"狗会跑"<<endl;}
private:double weight;
};int main()
{//从栈中实例化对象Dog dog1;dog1.name = "旺财";cout<<dog1.name<<endl;dog1.run();//dog1.weight = 50.2;//private和protect下面的成员类的对象无法访问//从堆中实例化对象,要用delete删除//不用delete删除的话,程序结束后系统会回收//不删除对象的话,这个指针会占这内存不放,会造成内存泄漏Dog* dog2 = new Dog;dog2->age = 3;cout<<dog2->age<<endl;delete dog2;return 0;
}/* 输出:
旺财
狗会跑
3
*/
二、构造函数和析构函数
定义了一个名称和类名相同,没有返回值的函数,这个函数称为构造函数。构造函数的特殊之处在于,它会在类实例化的时候被调用。
#include <iostream>
class Dog
{
public:Dog();
};
对象实例化的时候,会调用构造函数,而对象销毁的时候,就会调用析构函数。
对象销毁:程序结束了由系统释放;删除指针对象的时候
#include <iostream>
class Dog
{
public:~Dog();
};
举个栗子1:
#include <iostream>using namespace std;class Dog
{
public:Dog(){cout<<"构造函数被执行了"<<endl;}~Dog();};
Dog::~Dog()
{cout<<"析构函数被执行了"<<endl;
}int main()
{Dog dog1;return 0;
}
举个栗子2:
#include <iostream>using namespace std;class Dog
{
public:Dog(){cout<<"构造函数被执行了"<<endl;}~Dog();};
Dog::~Dog()
{cout<<"析构函数被执行了"<<endl;
}int main()
{//Dog dog1;Dog*dog2 =new Dog;return 0;
}
栗子1输出: 栗子2输出:
构造函数被执行了 构造函数被执行了
析构函数被执行了栗子1是从栈中实例化对象,程序结束了系统会回收对象
栗子2中析构函数没有执行,因为堆中实例化对象要用delete删除,栗子2中的对象没有被销毁
在类实例化对象的时候,如果没有定义构造函数,则编译器会合成一个默认的构造函数;当有了对象后,如果没有定义析构函数,则编译器会合成一个默认的析构函数。
三、this指针
this指针装着当前对象的地址,即每个对象都有自己的地址,我们可通过&t1,&t2...(对对象取地址)获取到各个对象的地址,C++在类内直接提供了地址,我们就不需要在类外获取了。C++面向对象编程提供了一个变量叫做this指针,该地址自动初始化成我们当前对象的地址,我们可以在类内直接使用this指针,就可使用当前对象的地址了。
这时候我们会想到,我直接取对象的地址,通过函数传递到类的内部去使用,为什么还存在this指针呢?这就是C++面向对象编程的思想了,对象表面是个变量,实际上它是区别于变量int、double等等,对象是拥有一个丰富功能的一个完整个体,一个对象自身就知道自己的地址,不需要“别人告诉”。
每个成员函数:析构、构造、自定义函数,都可以使用this指针,this指针作为函数的隐藏参数,传递给函数,每个成员都有,this的实现方法暂不研究。
this指针可用于区分类成员和局部变量
#include <iostream>
using namespace std;class Test
{
private://Test*this; "相当于类"内有this变量int a;
public:Test(/* Test*this ,*/int a){this->a = a; //用处1:区分 类成员和函数参数的局部变量}void Print(){cout<<a<<' '<<this<<endl;}
};int main()
{Test t(12);t.Print();cout<<"&t:"<<&t<<endl;return 0;/*输出:12 0x7fff76e94494&t:0x7fff76e94494*/
}
this指针可用于以下栗子:
#include <iostream>
using namespace std;class Test
{
private://Test*this; "相当于类"内有this变量int a;
public:Test(/* Test*this ,*/int a){//this->a = a; //用处1:区分 类成员和函数参数的局部变量(*this).a = a;}void Print(){cout<<a<<' '<<this<<endl;}Test*GetAddr(){return this; //用处3:返回当前对象的地址,外部使用}Test& GetObject(){return *this; //用处4:this是对象的地址,*this是对象本身}};int main()
{Test t(120);cout<<t.GetAddr()<<endl;//&tt.GetObject().Print() ;return 0;/*输出:ff2b1a2d14120 0x7fff2b1a2d14*/
}
四、类的继承
创建新类时,并不需要创建全新的数据和成员函数,我们可以指明这个新类继承现有类的成员。此时,现有的类称为“基类”,继承实现的新类称为“派生类”。
举个栗子:子类可以调用父类的成员
#include <iostream>
using namespace std;
//基类/父类
class Animal
{
public:string name;int age;void run(){cout<<"狗的年龄: "<<age<<endl;}
};//派生类/子类
class Dog:public Animal
{};int main()
{Dog dog1;dog1.age = 5;dog1.run();return 0;
}
(2)保护继承时基类中各成员属性均变为protected,并且基类中private成员被隐藏。派生类的成员只能访问基类中的public/protected成员,而不能访问private成员;派生类的对象不能访问基类中的任何的成员。
(3)私有继承时基类中各成员属性均变为private,并且基类中private成员被隐藏。派生类的成员也只能访问基类中的public/protected成员,而不能访问private成员;派生类的对象不能访问基类中的任何的成员。
五、函数重载
在同一个作用域内,声明几个功能类似的同名函数,并且这些同名函数的参数个数、参数类型或者参数顺序不同,那么就叫函数重载。
栗子1:
#include <iostream>using namespace std;class Dog
{
public:Dog(int weight)//构造函数重载{cout<<"int 狗的体重:"<<weight<<endl;}Dog(double weight)//构造函数重载{cout<<"double 狗的体重:"<<weight<<endl;}};
int main()
{Dog dog1(50);Dog dog2(50.5)return 0;
}/* 输出:
int 狗的体重:50
double 狗的体重:50.5
*/
栗子2:
#include <iostream>using namespace std;class Dog{
public:void getWeight(int weight){cout<<"int 狗的体重:"<<weight<<endl;}void getWeight(double weight){cout<<"double狗的体重:"<<weight<<endl;}
};
int main()
{Dog dog1;dog1.getWeight(100);dog1.getWeight(100.7);return 0;
}
学习更新行中·········