类与对象学习

(本文基于学过python面向对象,讲一些c++特有的)

1.创建类与对象

示例:

#include <iostream>
#include<string>
class Person
{
public:                        //成员限定修饰符
    Person(std::string name);  //构造函数 类的示例化时自动调用
    ~Person();                 //析构函数  对象销毁时自动调用
    void study();              //成员方法
private:
    std::string name;
};
Person::Person(std::string name)   //构造函数和析构函数不需要返回值
{
    this->name=name;            //this指针指向类实例化本身 第二个name为形参
}
Person::~Person()
{

}
void Person::study()        //在类外定义成员函数 需要加 作用域“::”
{
    std::cout<<name<<": i like studying"<<std::endl;
}
int main()
{
    Person stu("小明");      //类的实例化
    stu.study();
    return 0;
}

1.类的访问控制限定符
public:公有成员,在任何位置都可以访问
private:私有成员,只能类(自己)的成员函数中访问
protected:受保护成员,只能在类(自己)和子类中访问
注意:类中的成员变量、成员函数默认是 private,结构中的成员变量、成员函数默认是 public。
注意:C++中类和结构的区别只有成员函数和成员变量默认访问权限不同。


2.构造函数和析构函数
使用构造函数处理对对象的初始化。
构造函数是一种特殊的成员函数,与其他函数不同,不需要用户调用它,
而是创建对象的时候自动调用。
析构函数是对象不再使用的时候,需要清理资源的时候调用。


构造函数:
(1)构造函数是类的一个特殊的成员函数,函数名与类名相同;

(2)构造函数的访问属性应该是公有(public)访问属性;

(3)构造函数的功能是对对象进行初始化,因此在构造函数中只能对数据成员做初始化,
这些数据成员一般为私有成员,在构造函数中一般不做初始化以外的事情;

(4)构造函数可以在类内定义也可以在类外定义;

(5)构造函数无函数返回类型。注意:是什么也不写,也不可写void;

(6)在程序运行时,当新的对象被建立,该对象所属的类的构造函数自动被调用,在该对象生存期中也只调用这一次。

(7)构造函数可以重载。类中可以有多个构造函数,它们由不同的参数表区分,系统在自动调用时按一般函数重载的规则选一个执行。


析构函数:
(1)析构函数函数的名字特别,是类名加“~”字符,表明它与构造函数相反;

(2)析构函数没有参数,不能指定返回值类型;      

(3)一个类中只能定义一个析构函数,所以析构函数不能重载;

(4)在对象生存期结束时,系统自动调用析构函数。


3.作用域限定符 " :: "
当在类体中直接定义函数时,不需要在函数名字的前面加上类名,
但是在类体外实现函数定义的时候,必须加上类名并且加上作用域限定符。
Person::study();表明属于某个类的成员函数。

4.this指针
this 是 c++中的一个关键字,也是一个常量指针,指向当前对象,也就是当前对象的首地址。
通过this指针,可以访问当前对象的成员变量和成员函数。
特点:
1.  this指针的类型是 类类型* const

2.  this指针并不是对象本身的一部分,不会影响sizeof的结果

3.  this的作用域在类成员函数的内部

4.  this指针是类成员函数的第一个默认隐含参数,编译器自动维护传递

5.  只有在类的非静态成员函数中才可以使用this指针

注:
this 是常量指针,它的值不能被修改

this 只能在成员函数内部使用

只有对象被创建后this才有意义,因此不能再static成员函数中使用

这与python中的self参数一样
实际上,**this指针是作为函数的参数隐式传递的**,它并不出现在参数列表中,
调用成员函数时,系统(编译器)自动获取当前对象的地址,
并赋给this,完成参数的传递。
this作为隐式参数,本质上是成员函数的局部变量,不占用对象的内存,只有在发生成员函数调用时才会给this赋值,函数调用结束,this被销毁。

成员函数最终被编译成与对象无关的普通函数,除了成员变量,会丢失所有信息,
所以在编译时要在成员函数中添加一个额外的参数,把当前对象的首地址传入,
以此来关联成员函数和成员变量。
这个额外的参数也就是this  ,它是成员函数和成员变量之间的桥梁。

2.方法的重载与覆盖

方法重载是让类以统一的方式处理不同类型数据的一种手段。多个同名函数同时存在,具有不同的参数个数/类型。

成员函数重载特征:
a. 相同的范围(在同一个类中)

b. 函数名字相同

c. 参数不同

d. virtual关键字可有可无

重写(override),也叫覆盖: 子类重新定义父类中有相同名称和参数的虚函数(virtual)。在继承关系之间。C++利用虚函数实现多态

重写(覆盖)是指派生类函数覆盖基类函数,特征是:

a. 不同的范围,分别位于基类和派生类

b. 函数的名字相同

c. 参数相同

d. 基类函数必须有virtual关键字(虚函数)

运算符重载
函数重载就是对一个已有的函数赋予新的含义,使之实现新的功能。
而运算符重载的方法是定义一个重载运算符的函数,在需要执行被重载的运算符时,系统就自动调用该函数,以实现相应的运算。运算符重载时通过定义函数实现的,运算符重载实质上是函数的重载。

重载运算符的函数一般格式如下:

函数类型 operator 运算符名称 (形参列表)
{
	对运算符的重载处理
}
//将加法运算符改为减法
int operator+int a,int b)
{
    return (a-b);
}

运算符重载规则:
(1)C++不允许用户自己定义新的运算符,只能对已有的C++运算符进行重载

(2)除了对以下运算符不允许重载外,其他运算符允许重载:

--- .(成员访问运算符)

--- .*(成员指针访问运算符)

--- ::(域运算符)

--- sizeof (尺寸运算符)

--- ?:(条件运算符)

(3) 重载不能改变运算符运算对象(操作数)个数

(4) 重载不能改变运算符的优先级别

(5) 重载不能改变运算符的结合性

(6) 重载运算符的函数不能有默认参数

(7) 重载运算符必须和用户定义的自定义类型的对象一起使用,其参数至少应该有一个是类对象或类对象的引用。(也就是说,参数不能全部都是C++的标准类型,这样约定是为了防止用户修改用于标准类型结构的运算符性质)。

3.虚函数和纯虚函数

虚函数:C++动态联编 实现多态的重要手段,在函数声明时使用关键字
virtual即可。
格式: virtual void func(void);
注:虚函数只针对类的成员函数,普通函数不可声明为虚函数!且一般只

有在用到继承时才将基类的成员函数声明为虚函数!

class parentClass
{
 public:
     parentClass();
     ~parentClass();
 
    void func_1(void);
    virtual void func_2(void);
 private:
 };
 
 class childClass : public parentClass
 {
 public:
     childClass();
    ~childClass();

     void func_1(void);
    virtual void func_2(void);
 private:
 };
childClass childTest;
parentClass *pParentTest = &childTest;
pParentTest->func_1();
pParentTest->func_2();

pParentTest指针类型是parentClass基类类型,但它指向的地址对象却是childClass的对象,这种情况下:func_1函数不是虚函数,则调用的是指针类型所在类的函数,即第三句执行的是基类中的func_1函数;func_2函数是虚函数,则调用的是指针指向对象的所在类的函数,即第四句执行的是子类中的func_2函数。

基类中将某方法定义为虚函数,则在派生类中,该方法仍为虚方法。在使用时,定义基类类型的指针,使其指向派生类的对象,使用该指针调用某个方法,若该方法未被声明为虚函数,则调用的是指针类中的方法,若该方法是虚函数,则调用的是指针指向对象类中的该方法。这也即是动态联编。

1) 如上述4行代码,若有pParentTest->func_3();语句,其中func_3函数只在派生类中声明,基类中没有该方法,则会 编译报错 ;

2) 如上述4行代码,若有pParentTest->func_3();语句,其中func_3函数只在基类中声明,派生类中没有该方法,则会 调用基类的方法 ;

3) 如果基类声明被重载了,则应在派生类中重新定义所有的基类版本!如果派生类只重新定义了1个版本,则另外的版本将被隐藏,派生类对象无法调用;

4) 如果派生类要重新定义基类的方法,则派生类中的声明应与基类一致(函数名、参数、返回值),如果派生类的声明与基类参数不一致,则派生类的该方法将覆盖基类中的该方法(不构成重载),派生类对象只能按照派生类方法声明的格式进行调用!(基类中的该方法将被隐藏,派生类对象调用时会报错)

#include <iostream>
#include <string>

class animal
{
public:
    void sleep()
    {
        std::cout<<"animal sleeping";
    }
    virtual void breathe()     //声明为虚方法 子类重写时才会调用子类中重写的方法
    {
        std::cout<<"animal breathe";
    }

};

class fish :public animal
{
public:
    virtual void breathe()
    {
        std::cout<<"fish bubble";
    }
};

int main()
{
    fish fh;
    animal *p = &fh;
    p->breathe();
    return 0;
}

虚方法的一般使用条件:

1) 需要在派生类中重新定义基类的方法,则在基类中将该方法声明为虚方法;

2) 涉及到派生的,一般都将析构函数声明为虚函数;

3) 构造函数不能为虚函数!

4) 友元函数不能是虚函数,因为它不是类的成员函数!

**纯虚函数:**也叫抽象函数,在面向对象的概念中,我们知道所有的对象

都是通过类来描绘的,但是反过来却不是这样。并不是所有的类都是用来

描绘对象的, 如果一个类中没有包含足够的信息来描绘一个具体的对象,

这样的类就是抽象类 。纯虚函数是在基类中声明的虚函数,它在基类中
没有定义,但要求任何派生类都要定义自己的实现方法。在基类中实现纯
虚函数的方法是在函数原型后加“=0”。

格式:virtual void funtion1()=0

包含纯虚函数的类称为抽象类。由于抽象类包含了没有定义的纯虚函数,

所以不能定义抽象类的对象。

#include <iostream>
#include <string>
class Pet
{
public:

    Pet(std::string name)
    {
        this->name = name;
    }

    virtual void eat()= 0;//抽象函数

protected:
    std::string name;
};

class Cat :public Pet
{
public:
   Cat(std::string name);
    void eat()
    {
        std::cout<<this->name<<"吃鱼\n";
    }
};


class Dog :public Pet
{
public:
    Dog(std::string name);
    void eat()
    {
        std::cout<<this->name<<"吃肉";
    }

};
Cat::Cat(std::string name) : Pet(name)  //子类中的构造函数(必须写外面吗)
{

}
Dog::Dog(std::string name):Pet(name)
{

}
int main()
{
    Cat cat("Tom");
    Dog dog("jan");
    Pet *p =&cat;
    Pet *q=&dog;
    p->eat();
    q->eat();
    return 0;
}


4.静态成员与静态变量

5.友元类

6.继承与虚继承

继承:子类继承父类,子类的对象可以直接访问父类公有或保护成员
继承语法:

继承语法:
     派生类 : [继承方式] 基类
     class Studen : public Person
     {
     
	 }
	 继承方式:
       1.private:私有继承.默认为此继承方式.不能继承基类的私有成员.
            继承基类公有成员,在派生类中相当于是私有成员.
            继承基类保护成员,在派生类中相当于是私有成员.

       2.public:公有继承.不能继承基类的私有成员.
            继承基类公有成员,在派生类中相当于是公有成员.
            继承基类保护成员,在派生类中相当于是公有成员.

       3.protected:保护继承,不能继承基类的私有成员.
             继承基类公有成员,在派生类中相当于是保护成员.
             继承基类保护成员,在派生类中相当于是保护成员.

一个类有多个基类,这样的继承关系称为多继承;
多继承声明语法:

class 派生类名: 访问控制符 基类名1,访问控制符 基类名2
{
	数据成员和成员函数声明;
}
class A: public B,public c
{

}

多个直接基类构造函数执行顺序取决于定义派生类时指定的各个继承基类的顺序。

  • 2
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Super.Bear

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值