C++:随笔5---this指针和类的继承

this指针:(通过一个典型的例子来认识他)

class Human
{
    char fishc;
    Human(char fishc);//构造函数

};
Human::Human(char fishc)//对构造函数进行初始化
{
   fishc=fishc;//意图就是把这个传入参数赋值给这个上边类属性的fishc
}
//但是这样赋值的话,他们的名字一样,这样的话构造器就有可能认不出来,(因为他不知道你是要把属性去覆盖参数,还是把传入的参数去覆盖给属性,因为两者的名字一样,但是语法没有错。他们是两个不同区域的一个是传入的参数,一个是类的属性,(因为他们位于两个不同的区域,所以语法上没有错))

//所以怎么让构造器知道哪个是参数哪个是属性呢?这个时候就需要用到this指针。
this->fishc=fishc;//this指针是指向当前的类生成的对象//所以就很明显前者是类的属性,后边是参数。
//这样的话编译器就懂了,赋值操作符的左边将被解释为当前对象的fishc属性,右边将被解释为构造器的传入来的fishc的参数。

//PS:注意使用this指针的基本原则是如果代码不存在二义性隐患,就不必使用this指针。

------------类的继承-------

继承机制使得程序员可以创建一个类的堆叠层次结构,每个子类均将继承在他的基类里定义的方法和属性。(在继承原有方法的同时,再增加另外的一些属性的方法)(通过继承机制可以对现有的代码进行进一步的扩展,并应用在新的程序中)

(1)他们都是动物的子类。我们可以编写一个Animal作为Turtle和Pig的基类。

继承类的语法:

//语法:
class SubClass:public Superclass{...}
//例子:
class Pig:public Animal{...}

基类是可以派生出其他的类,也称为父类和超类;子类是从基类派生出来的类(比如Turtle类和Pig类)。

  

实现如下:

#include<iostream>
#include<string>
class Anmial//声明一个基类
{
 public:
    std::string mouth;
    void eat();
    void sleep();
    void drool();
};
//继承基类
class Pig:public Animal
{
 public:
   void climb();
};
class Turtle:public Animal
{
 public:
   void swim();
};
//对上述方法进行补充
void Animal::eat()
{
   std::cout<<"我正在吃"<<std::endl;
}
void Animal::sleep()
{
   std::cout<<"我正在睡觉"<<std::endl;
}
void Animal::eat()
{
   std::cout<<"我正在流口水"<<std::endl;
}//上述把基类的三个方法给搞定了
//下面实现子类的方法(不管他们是基类还是父类,他们都是方法就按照类的方法实现来写)
void Pig::climb()
{
   std::cout<<"我会爬树"<<std::endl;
}
void Turtle::swim()
{
   std::cout<<"我会游泳"<<std::endl;
}
int main()
{
   //对类进行实例化
   Pig pig;
   Turtle turtle;
   
   pig.sleep();
   turtle.sleep();
   pig.climb();
   turtle.swim();
   
}

------带参数的构造器----

扫描二维码关注公众号,回复: 11962676 查看本文章
//构造器带着输入参数
//1、声明
class Animal
{
  public:
     Animal(std::string thename);
     std::string name;
};
class Pig:public Animal
{
  public:
     Pig(std::string thename);

};
//2、方法定义
Animal::Animal(std::string thename)
{
   name=thename;
}
Pig::Pig(std::string thename):Animal(thename)//Pig的构造器继承Animal的构造器
{

}

因为Pig的方法里面是空的,他是直接继承于Animal的方法的。

------访问控制--------

上述类的所有成员都是用public:语句声明。

所谓的访问控制就是c++提供了一种用来保护类里的方法和属性的手段。

  

-------覆盖------

既有共同特征又需要在不同类里有不同的实现方法)意思就是在类里边重新声明一下这个方法,他的函数名字参数返回值一摸一样(不然的话就会变成重载了)。

例子:为Animal添加eat方法,并在子类中进行覆盖。

-------重载方法--------

继承之后不能重载。(子类里边不能重载)

----友元-------

   

声明另外一个类是这个类的友元类,友元关系是类之间的一种特殊关系,这种特殊关系不仅允许友元类访问对方的public方法和属性,还允许友元访问对方的protected和private方法和属性。

声明一个友元关系的语法,在类声明里的某个地方加上一条friend class **就行了(其中**表示你需要友元的另一个类的那个名字)。

注意这条语句可以放在任何地方,放在public,protected和private段落里边都可以。(这样之后他们两个人就相当于是同一个人)

例子:定义Lovers这个类,有两个子类Boyfriend和Girlfriend。Lovers类的方法kiss()和ask();第三者Others类,想要kiss()Girlfriend类的对象。

#include<stdio.h>
#include<iostream>

class Lovers
{
 public:
     Lovers(std::string theName);//构造函数,就是给他命名
     void kiss(Lovers* lover);//参数声明一个指针,
     void ask(Lovers* lover,std::string something);
 protected:
      std::string name;
      friend class others;//这时候others跟Lovers就是一对。
};
class Boyfriend:public Lovers
{
 public:
      Boyfriend(std::string theName);
};
class Girlfriend:public Lovers
{
 public:
      Girlfriend(std::string theName);
};
class Others
{
  public:
      Others(std::string theName);
      void kiss(Lovers* lover);
  protected:
      std::string name;//Lover->name属于这个类的protected
};
Lovers::Lovers(std::string theName);
{
   name=theName;//构造函数给它命名,也就是说我们造一个人出来的时候,
}
void Lovers::kiss(Lovers* lover)
{
   std::cout<<name<<"亲亲"<<lover->name<<std::endl;
}
void Lovers::ask(Lovers* lover,std::string something)
{
   std::cout<<Lover->name<<"帮我"<<something<<std::endl;
}
//子类
Boyfriend::Boyfriend(std::string name):Lovers(theName)
{

}
Girlfriend::Girlfriend(std::string name):Lovers(theName)
{

}
//友元类
Others::Others(std::string theName);
{
   name=theName;//构造函数给它命名,也就是说我们造一个人出来的时候,
}

void Others::kiss(Lovers* lover)//这个里边的参数引用到了lover
{
   std::cout<<name<<"吻一下"<<lover->name<<std::endl;//lover->name属于这个Lovers类的protected,不是这个类的子类根本访问不到,而others不是它的子类,所以理论上是访问不到的,这里因为上边是friend class others;所以可以访问到。
}
//主函数
int main()
{
   Boyfriend boyfriend("A君");//造一个人出来给它命名叫做A君(构造函数)
   Girlfriend girlfriend("B妞");//叫做B妞

   Others others("路人甲");//others这个陌生人叫做路人甲

   girlfriend.kiss(&boyfriend);//因为参数是指针所以传进去的应该是对象的地址
   girlfriend.ask(&boyfriend,"拖地")

   std::cout<<"传说中的友元类,路人甲出现了\n"<<std::endl;
   others.kiss(&girlfriend);
   return 0;
}

-------静态属性和静态方法-------

创建一个静态属性和静态方法:只需要在他的声明前加上static保留字即可。

#include<string>
#include<iostream>

class Pet
{
 public:
	Pet(std::string theName);//带参数的构造器
	~Pet();
	static int getCount();//这里作为一个接口,用来给他由他生成的对象来获取他这个计数器
 protected:
	std::string name;
 private://private是这个类里的方法才能够调用的,getCount()函数可以调用//private成员只有这个类里边的方法才能够访问它
	static int count;//私有成员,一个count计数器
};
class Dog :public Pet//继承Pet类
{
 public:
	Dog(std::string theName);
	~Dog();
};
class Cat :public Pet//继承Pet类
{
 public:
	Cat(std::string theName);
	~Cat();
};
int Pet::count = 0;//这一句做了两件事;第一:让编译器为count这个变量的值分配内存;第二:这个变量因为是在静态存储区,他是把这个变量初始化为0;
Pet::Pet(std::string theName)//构造函数,当该构造函数被调用的时候说明这个宠物已经被建造出来了
{
	name = theName; 
	count++;//那么这个计数器就加一
	std::cout << "一只宠物变出来了,名字叫做:" << name << std::endl;
}
Pet::~Pet()//析构器
{
	count--; //析构器说明这个宠物已经挂掉了,所以计数器要减掉
	std::cout << name << "挂掉了" << std::endl;
}
int Pet::getCount()//这个接口函数getCount()的唯一作用,把这个count返回出来,把他拿到的这个私有成员返回出来,然后show出来
{
	return count;//是为了任何代码都可以通过调用getCount()函数(因为是public)从而来读取该属性count的值(因为该值是private,所以对该属性只能是读不能是写,只有在Pet的析构函数和构造函数才能够对他进行写)
}
Dog::Dog(std::string theName) :Pet(theName)//Dog的构造器继承Pet的构造器
{
     //std::cout<<"this:"<<this<<endl;//1生成一个dog对象之后就把this指针给打印出来//按此它生成一个dog对象的时候this指针应该是指向dog对象的。下边生成dog对象
}
Dog::~Dog()
{

}
Cat::Cat(std::string theName) :Pet(theName)
{

}
Cat::~Cat()
{

}
int main()
{
	Dog dog("Tom");//整了一只狗dog叫做Tom(继承构造器的实现)//用Dog类生产出dog对象
	Cat cat("Jerry");//整了一只猫叫做Jerry
        std::cout<<"dog:"<<&dog<<std::endl;//2这里生成dog对象之后,我们把dog也给打印出来
	std::cout << "已经诞生了" << Pet::getCount() << "只宠物!\n\n";//显示出来//getCount()函数调用私有成员count
	{//注意这里的大括号,是有作用的。这里相当于是一个区域
		Dog dog_2("Tom_2");//又整了一只狗
		Cat cat_2("Jerry_2");//又整了一只猫
		std::cout << "现在呢,已经诞生了" << Pet::getCount() << "只宠物!\n\n";
	}//到此之前还剩下两只,因为大括号之后析构函数了,把宠物给毁掉
	std::cout << "\n现在还剩下" << Pet::getCount() << "只宠物!\n\n";
	return 0;//return 0的时候一只宠物都没有了,因为析构函数了,把宠物给毁掉
}
//上述1和2处打印的地址完全一样

结果:右边结果是去掉main函数中间的大括号的

   

static静态变量的详解:https://www.cnblogs.com/dc10101/archive/2007/08/22/865556.html

静态成员是所有对象共享的,所以不能在静态方法里访问非静态的元素。

非静态方法可以访问类的静态成员,也可以访问类的非静态成员。

C++内存分配方式详解——堆、栈、自由存储区、全局/静态存储区和常量存储区https://fishc.com.cn/blog-9-1097.html

this指针:this指针是类的一个自动生成,自动隐藏的私有成员,它存在于类的非静态成员函数中,指向被调用函数所在的对象的地址。(也就是说我生成每一个对象的时候,它都会自动生成一个this指针,这个指针指向的是对象它的一个地址)当一个对象被创建时,该对象的this指针就会自动指向对象数据的首地址。

#include<iostream>
class Point
{
  private:
     int x,y;
  public:
     point(int a,intb)
     {
        x=a;
        y=b
     }
     void MovePoint(int a,int b)
    {
        x=a;
        y=b;
    }
    void print()
    { 
       std::cout<<"x="<<x<<"y="<<y<<endl;
    }
};
int main()
{
    Point point1(10,10);//用Point这个类生产出Point1这个对象。这个点的坐标在(10,10)这个位置
    Point1.MovePoint(2,2);
    point1.print();
    return 0;
}
//当对象point1调用MovePoint这个成员的时候,(实时上我们生成point1这个对象的时候,就有一个this指针指向point1的地址),当他调用MovePoint这个函数的时候,即将point1对象的地址传递给this指针,(因为我们需要用到的是point1这个对象的成员,那我们就必须知道这个对象的地址,就必须传递给this指针)
//MovePoint函数的原型事实上应该是 void MovePoint(Point* this,int a,int b);他有三个参数,一个是隐含的this指针它指向Point对象(第一个参数是指向该类对象的一个指针,我们在定义成员函数时没看见是因为这个参数在类中是隐含的,是C++的一个规则,因为每一个都是默认添加进第一个规则)。
//这样子pOint1的地址就传递给this,所以在MovePoint()函数中便可以显示的写成void MovePoint(int a,int b)(this->x=a;this->y=b)(其实也可以x=a,这样编译器知道哪一个是参数哪一个是变量,用this做区分)
//我们这样就可以知道point1调用该函数后,也就是point1的数据成员被调用并更新了值。

猜你喜欢

转载自blog.csdn.net/m0_37957160/article/details/108912373
今日推荐