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();}

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

//构造器带着输入参数
//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");//整了一只猫叫做Jerrystd::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的数据成员被调用并更新了值。

C++:随笔5---this指针和类的继承相关推荐

  1. C++智能指针管理类

    1.程序猿明白的进行内存释放 对于c++程序猿,最头脑的莫过于对动态分配的内存进行管理了.c++在堆上分配的内存.须要程序猿负责对分配的内存进行释放.但有时内存的释放看起来并不件非常轻松的事,例如以下 ...

  2. C++ 类的行为 | 行为像值的类、行为像指针的类、swap函数处理自赋值

    文章目录 概念 行为像值的类 行为像指针的类 概念 引用计数 动态内存实现计数器 类的swap 概念 swap实现自赋值 概念 行为像值的类和行为像指针的类这两种说法其实蛮拗口的,这也算是 <C ...

  3. c++面向对象高级编程 学习二 带指针的类

    带指针的类,必须要自己写拷贝构造和赋值构造 拷贝构造:参数和类的类型一样的构造函数 赋值构造:重写操作符=,且其参数和类的类型一样 class String {public: String(const ...

  4. c++面向对象高级编程 学习一 不带指针的类

    复数类 complex 是一个不带指针的类,其声明如下: class complex {public: complex(double r=0,double i=0):re(r),im(i){} com ...

  5. 《C++ Primer Plus》16.2 智能指针模板类

    智能指针是行为类似于指针的类对象,单这种对象还有其他功能.本节介绍三个可帮助管理动态内存分配的智能指针类.先来看看需要哪些功能以及这些功能是如何实现的.请看下面的函数: void remodel(st ...

  6. C++基础知识 —— 内存分区模型、引用、函数重载、类和继承、this指针、友元、多态、文件操作

       参考 黑马程序员 C++课程笔记,个人理解及整理  可以使用 在线编译c++代码 来简单验证.学习代码 目录 C++核心编程 1. 内存分区模型 1.1 程序运行前 1.2 程序运行后 1.3 ...

  7. 随笔:幽灵一样的基类

    关于面向对象 很多程序员应聘的时候,除了会写精通某种语言之外,往往还会写上熟悉和精通就是面向对象的软件设计,结果与之交谈之后才发现,根本不是那么回事,他会定义类,也会从一个类派生另一个类,然后会使用这 ...

  8. 详解函数指针和类成员函数指针

    作者:倾夜·陨灭星尘 一.什么是函数指针? 函数指针,顾名思义即指向函数的指针. 如果要问,为什么能用一个指针指向一个函数呢?我觉得要理解这个问题,以及要理解后面的函数指针和类成员函数指针,没有什么比 ...

  9. C++智能指针模板类

    对于常规类指针,可能由于忘记释放内存而导致内存泄漏,有三种智能指针可以解决这类问题. 对于常规指针,它没有析构函数,加入指针成为了对象,那么,在对象过期时就会自动调用析构函数,让析构函数释放指针指向的 ...

最新文章

  1. vue css 应用变量_如何使用CSS Grid和CSS变量快速为应用创建原型
  2. 百度 什么是主成分分析
  3. php制作明信片,用PS如何制作明信片?PS制作明信片图文介绍
  4. Scikit-learn新版本发布,一行代码秒升级
  5. 华为MSTP配置教程(二)
  6. 嵌套 移动端_360PC端小程序全面开放使用
  7. LeetCode 集锦(二十二) - 第 101 题 Symmetric Tree
  8. QT的QHttpMultiPart类的使用
  9. kafka直连方式消费多个topic
  10. Navicat工具获取操作数据库和表的SQL语句
  11. MYSQL存储过程初步认知
  12. Form各键盘触发子所对应的“按键”
  13. PAT (Basic Level) Practice1020 月饼
  14. js 中通过 var 在声明的变量中写方法
  15. mysql outfile 权限_MYSQL解决select ... into outfile '..' mysql写文件权限问题 Can't create/write to file...
  16. springmvc学习一初始化源码
  17. 推荐一款UI非常Good的 Redis 客户端工具
  18. 2020中兴捧月算法大赛——傅里叶赛道 第1名方案
  19. 火车头采集html5游戏,火车头采集工具Wed发布配置方法
  20. 解决 VUE 微信 IOS 路由跳转问题

热门文章

  1. TypeError: ord() expected string of length 1, but int found
  2. java 内部类的理解
  3. Java中byte与16进制字符串的互相转换
  4. JQ实现当前页面导航加效果(栏目页有效)
  5. 深入浅出的webpack构建工具---DllPlugin DllReferencePlugin提高构建速度(七)
  6. centos 6.8 启动损坏修复实验
  7. MySQL数据库开发常见问题及几点优化!
  8. 算法(第四版)C# 习题题解——1.3
  9. C++中模块(Dll)对外暴露接口的方式
  10. 什么是IOC为什么要使用IOC