类及对象------My_CPP

每天反复做的事情造就了我们,然后你就会发现,优秀并非一种行为,而是一种习惯。

                                                                                                                         ------------亚里士多德(Aristotle(阿瑞斯透头))

 

银行里柜台里坐着的数钱的----(点钞员)


在计算机世界里我们将具备这些特质的人   抽象为一个类

我们用类创建的每个对象将拥有这些特质

class BankPerson
{
   public:
       CheckMoney()
     {
        //数钱
     }

};

void main()
{
  BankPerson  B1;//创建对象  数钱人1
  BankPerson  B2;//创建对象  数钱人2
   //他们都具备一个功能数钱
}

C++中struct和class的区别是什么?

C++需要兼容C语言,所以C++中struct可以当成结构体使用。另外C++中struct还可以用来 定义类。

和class定义类是一样的,区别是struct定义的类默认访问权限是public,class定义的类 默认访问权限是private。

注意:在继承和模板参数列表位置,struct和class也有区别,后序给大家介绍。

类的定义

class className
{
// 类体:由成员函数和成员变量组成
};  // 一定要注意后面的分号


class为定义类的关键字,ClassName为类的名字,{}中为类的主体,注意类定义结束时后面分
号不能省略。
类体中内容称为类的成员:类中的变量称为类的属性或成员变量; 类中的函数称为类的方法或者
成员函数。

类的作用域

类定义了一个新的作用域,类的所有成员都在类的作用域中。在类体外定义成员时,需要使用 :: 
作用域操作符指明成员属于哪个类域。
class Person
{
public:
 void PrintPersonInfo();
private:
 char _name[20];
 char _gender[3];
 int  _age;
};
// 这里需要指定PrintPersonInfo是属于Person这个类域
void Person::PrintPersonInfo()
{
 cout << _name << " "<< _gender << " " << _age << endl;
}

类的实例化

用类类型创建对象的过程,称为类的实例化

1. 类是对对象进行描述的,是一个模型一样的东西,限定了类有哪些成员,定义出一个类并没有分配实际的内存空间来存储它;比如:入学时填写的学生信息表,表格就可以看成是一个 类,来描述具体学生信息。

2. 一个类可以实例化出多个对象,实例化出的对象 占用实际的物理空间,存储类成员变量

int main()
{
 Person._age = 100;   // 编译失败:error C2059: 语法错误:“.”
 return 0;
}


Person类是没有空间的,只有Person类实例化出的对象才有具体的年龄。





做个比方。类实例化出对象就像现实中使用建筑设计图建造出房子,类就像是设计图,只设
计出需要什么东西,但是并没有实体的建筑存在,同样类也只是一个设计,实例化出的对象
才能实际存储数据,占用物理空间

this指针

class Date
{ 
public:
 void Init(int year, int month, int day)
 {
 _year = year;
 _month = month;
 _day = day;
 }
 void Print()
 {
 cout <<_year<< "-" <<_month << "-"<< _day <<endl;
 }

private:
 int _year;     
 int _month;    
 int _day;      
};
int main()
{
 Date d1, d2;
 d1.Init(2022,1,11);
 d2.Init(2022, 1, 12);
 d1.Print();
 d2.Print();
 return 0;
}

对于上述类,有这样的一个问题:

Date类中有 Init 与 Print 两个成员函数,函数体中没有关于不同对象的区分,那当d1调用 Init 函 数时,该函数是如何知道应该设置d1对象,而不是设置d2对象呢?

C++中通过引入this指针解决该问题,即:C++编译器给每个“非静态的成员函数“增加了一个隐藏 的指针参数,让该指针指向当前对象(函数运行时调用该函数的对象),在函数体中所有“成员变量” 的操作,都是通过该指针去访问。只不过所有的操作对用户是透明的,即用户不需要来传递,编 译器自动完成。

this指针特性

  • this指针的类型:类类型* const,即成员函数中,不能给this指针赋值。(Date* const this)
  • 只能在“成员函数”的内部使用 
  • this指针本质上是“成员函数”的形参,当对象调用成员函数时,将对象地址作为实参传递给 this形参。所以对象中不存储this指针。 
  • this指针是“成员函数”第一个隐含的指针形参,一般情况由编译器通过ecx寄存器自动传 递,不需要用户传递
1. this指针存在哪里?

其实编译器在生成程序时加入了获取对象首地址的相关代码。并把获取的首地址存放在了
寄存器ECX中(VC++编译器是放在ECX中,其它编译器有可能不同)。也就是成员函数的其它
参数正常都是存放在栈中。而this指针参数则是存放在寄存器中。


类的静态成员函数因为没有this指针这个参数,所以类的静态成员函数也就无法调用类的非静态成员变量。


-------------------------------------------------------------------------------------------

2. this指针可以为空吗?

可以为空,当我们调用函数时,如果函数内部不需要使用到this,也就是不需要通过this指向当前对象
并对其进行操作时才可以为空(当我们在其中什么都不做或者在里面随便打印一个字符串),如果调用的
函数需要指向当前对象,并进行操作,则会发生错误(空指针引用)就跟C中一样不能进行空指针的引用


class A
{
public:
 void Print()
 {
 cout << "Print()" << endl;
 }
private:
 int _a;
};
int main()
{
 A* p = nullptr;
 p->Print();
 return 0;
}

初始化列表

初始化列表:以一个冒号开始,接着是一个以逗号分隔的数据成员列表,每个"成员变量"后面跟 一个放在括号中的初始值或表达式

class Date
{
public:

Date(int year, int month, int day): _year(year),_month(month), _day(day){}

private:
int _year;
int _month;
int _day;
};

成员变量在类中声明次序就是其在初始化列表中的初始化顺序,与其在初始化列表中的先后次序无关 

explicit关键字

构造函数不仅可以构造与初始化对象,对于单个参数或者除第一个参数无默认值其余均有默认值 的构造函数,还具有类型转换的作用。

用explicit修饰构造函数,将会禁止构造函数的隐式转换。

禁止隐式转换后就不能编译通过了

static成员 

声明为static的类成员称为类的静态成员,用static修饰的成员变量,称之为静态成员变量;用 static修饰的成员函数,称之为静态成员函数静态成员变量一定要在类外进行初始化

class A
{
public:
A() { ++_scount; }
A(const A& t) { ++_scount; }
~A() { --_scount; }
static int GetACount() { return _scount; }
private:
static int _scount;
};
int A::_scount = 0;
void TestA()
{
cout << A::GetACount() << endl;
A a1, a2;
A a3(a1);
cout << A::GetACount() << endl;
}

特性

  • 静态成员为所有类对象所共享,不属于某个具体的对象,存放在静态区 
  • 静态成员变量必须在类外定义,定义时不添加static关键字,类中只是声明 
  • 类静态成员即可用 类名::静态成员 或者 对象.静态成员 来访问 
  • 静态成员函数没有隐藏的this指针,不能访问任何非静态成员 
  • 静态成员也是类的成员,受public、protected、private 访问限定符的限制


静态成员函数可以调用非静态成员函数吗?

 可以通过传递this指针的方法

静态成员函数是类的成员,但非类的对象的成员,//因为没有this指针,若我们能传递this指针依然可以对其进行调用

#include <string>
#include <iostream>

using namespace std;
class A
{
public:
	
	static void test(void* arg)
	{
		A* p = (A*)arg;
		cout << p << endl;
		cout << p->m_data<<endl;
	}
	void test2()
	{
		test(this);
		cout << "this pointer" << endl;
			cout << this << endl;
	}
private:
	int m_data = 888;
};
int main()
{
	A a;
	a.test2();
	return 0;
}

在类中使用静态成员函数是一种破坏封装的行为,因为静态成员函数只能调用类的静态成员。
但是在有些情况下只能使用静态成员函数,比如类内绑定自身成员函数作为回调函数,这种
情况在开启多线程时很常见,如果不想将回调定义为全局那只能定义为类静态了,为了避免
过度破坏封装类中应当尽量不要让类静态成原函数调用类成员。这种情况下可以用一种比较
取巧的方法。

因为类的静态成员和普通成员其实就一种区别,那就是静态成员本身没有this指针,所以
静态成员属于类而不属于类对象。如果我们想在类的静态成员函数里面调用类的普通成员,
只需要把类指针当做参数传入静态成员函数里面,静态成员函数可以使用这个指针调用类的
普通成员,

非静态成员函数可以调用类的静态成员函数吗?

非static成员函数可访问static态成员函数/成员;

#include <string>
#include <iostream>

using namespace std;
class A
{
public:
	
	
	void test2()
	{
		cout << y_data<<endl;
		
	}
private:
	
	static int y_data;
};
int A::y_data = 999;

int main()
{
	A a;
	a.test2();
	return 0;
}

友元

http://t.csdn.cn/PHnNF

去看这个博主,他  他妈写的太好了!!!!

生活中你的家有客厅(public),有你的卧室(private)
客厅所有来的客人都可以进去,但是你的卧室是私有的,也就是说只有你能进去

但是呢,你也可以允许 隔壁老王 进去。

在程序里,有些私有属性 也想让类外特殊的一些函数或者类进行访问,就需要用到友元的技术

友元的目的 就是让一个函数或者类 访问另一个类中的私有成员

友元的关键字为 friend

友元提供了一种突破封装的方式,有时提供了便利。但是友元会增加耦合度,破坏了封装,所以
友元不宜多用。
友元分为:友元函数友元类


全局函数做友元

#include <iostream>
#include <string>

using namespace std;

// 房屋类
class Building
{
	// 告诉编译器 laoWang全局函数是 Building类  的好朋友,可以访问Building对象的私有成员
	friend void laoWang1(Building *building);
	friend void laoWang2(Building &building);
	friend void laoWang3(Building building);

public:

	Building()
	{
		m_SittingRoom = "客厅";
		m_BedRoom = "卧室";
	}
	
	string m_SittingRoom;	// 客厅

private:

	string m_BedRoom;		// 卧室
};



//全局函数
void laoWang1(Building *building)
{
	cout << "隔壁老王 全局函数 正在访问:(地址传递) " << building->m_SittingRoom << endl;

	cout << "隔壁老王 全局函数 正在访问:(地址传递) " << building->m_BedRoom << endl;
}

void laoWang2(Building &building)
{
	cout << "隔壁老王 全局函数 正在访问:(引用传递) " << building.m_SittingRoom << endl;

	cout << "隔壁老王 全局函数 正在访问:(引用传递) " << building.m_BedRoom << endl;
}

void laoWang3(Building building)
{
	cout << "隔壁老王 全局函数 正在访问:( 值传递 ) " << building.m_SittingRoom << endl;

	cout << "隔壁老王 全局函数 正在访问:( 值传递 ) " << building.m_BedRoom << endl;
}

void test()
{
	Building building;
	laoWang1(&building);
	laoWang2(building);
	laoWang3(building);
}


int main()
{
	test();
}

 类做友元

#include <iostream>
#include <string>

using namespace std;

// 类作友元

class Building;
class LaoWang
{
public:

	LaoWang();

	void visit();	//参观函数  访问Building中的属性

	Building * building;


private:


};

// 房屋类
class Building
{
	// 告诉编译器,LaoWang类是Building类的好朋友,可以访问Building类的私有成员
	friend class LaoWang;
public:
	
	Building();
		
	string m_SittingRoom;	// 客厅
	
private:
	
	string m_BedRoom;		// 卧室
};

// 类外定义成员函数

Building::Building()
{
	m_SittingRoom = "客厅";
	m_BedRoom = "卧室";
}

LaoWang::LaoWang()
{
	// 创建建筑物对象
	building = new Building;
}

void LaoWang::visit()
{
	cout << "隔壁老王LaoWang类正在访问:" << building->m_SittingRoom << endl;

	cout << "隔壁老王LaoWang类正在访问:" << building->m_BedRoom << endl;
}

void test()
{
	LaoWang lw;
	lw.visit();
}

int main()
{
	test();

	return 0;
}

成员函数做友元

被声明为friend的类的函数可以访问该类的私有成员

visit1()//被声明为Building的朋友 ,可以访问Building的私有成员

visit2()//并非Building的朋友

#include <iostream>
#include <string>

using namespace std;

class Building;

class LaoWang
{
public:

	LaoWang();
	void visit1();	//让visit1()函数   可以 访问Building中的私有成员
	void visit2();	//让visit2()函数 不可以 访问Building中的私有成员

	Building *building;

private:

	
};

class Building
{
	// 告诉编译器,LaoWang类下的visit1()函数是Building类的好朋友,可以访问Building的私有成员
	friend void LaoWang::visit1();

public:
	Building();

	string m_SittingRoom;	//客厅
private:

	string m_BedRoom;		//卧室
};


LaoWang::LaoWang()
{
	building = new Building;
}

void LaoWang::visit1()
{
	cout << "隔壁老王LaoWang类中的visit1()函数正在访问:" << building->m_SittingRoom << endl;
	cout << "隔壁老王LaoWang类中的visit1()函数正在访问:" << building->m_BedRoom << endl;
}

void LaoWang::visit2()
{
	cout << "隔壁老王LaoWang类中的visit2()函数正在访问:" << building->m_SittingRoom << endl;
	//cout << "隔壁老王LaoWang类中的visit2()函数正在访问:" << building->m_BedRoom << endl;	//错误!私有属性不可访问
}

Building::Building()
{
	m_SittingRoom = "客厅";
	m_BedRoom = "卧室";
}

void test()
{
	LaoWang lw;
	
	lw.visit1();

	lw.visit2();
}

int main()
{
	test();
	
	return 0;
}

特征

  • 友元函数可访问类的私有和保护成员,但不是类的成员函数
  • 友元函数不能用const修饰
  • 友元函数可以在类定义的任何地方声明,不受类访问限定符限制
  • 一个函数可以是多个类的友元函数
  • 友元函数的调用与普通函数的调用原理相同
  • A是B的友元类(A----B的private)  但是我A可没说你B是我A的朋友(B  !--->A)

内部类

概念:如果一个类定义在另一个类的内部,这个内部类就叫做内部类。内部类是一个独立的类,
它不属于外部类,更不能通过外部类的对象去访问内部类的成员。外部类对内部类没有任何优越
的访问权限。
注意:内部类就是外部类的友元类,参见友元类的定义,内部类可以通过外部类的对象参数来访
问外部类中的所有成员。但是外部类不是内部类的友元。

特征

  • 内部类可以定义在外部类的public、protected、private都是可以的。
  • 注意内部类可以直接访问外部类中的static成员,不需要外部类的对象/类名。
  • sizeof(外部类)=外部类,和内部类没有任何关系。
class A
{
private:
 static int k;
 int h;
public:
 class B // B天生就是A的友元
 {
 public:
 void foo(const A& a)
 {
 cout << k << endl;//OK
 cout << a.h << endl;//OK
 }
 };
};
int A::k = 1;
int main()
{
    A::B b;
    b.foo(A());
    
    return 0;
}

匿名对象

//匿名对象产生的三种场景
#include<iostream>
using namespace std;

class Point{
public:
    Point(int a,int b){
        cout << "有参构造函数被调用了1" << endl;
        this->x = a;
        this->y = b;
    }
    Point(Point &a1){
        cout << "拷贝构造函数被调用了2" << endl;
        this->x = a1.x;
        this->y = a1.y;
    }
    ~Point(){
        cout << "析构函数被调用了3" << endl;
        cout << "x=" << x << endl;
        cout << "y=" << y << endl;
    }
    Point Protset(int a){
        this->x = a;
        return *this;
        //执行 return *this; 会产生一个匿名对象,作为返回值
        //强调:如果返回值是引用,则不会产生匿名对象
    }

    Point Protset2(int a){
        Point temp(a, a);
        return temp;
        //执行 return temp;会先产生一个匿名对象,执行拷贝构造函数,作为返回值,
        //然后释放临时对象temp
    }

    //总结:函数返回值为一个对象(非引用)的时候会产生一个匿名对象,匿名对象根据主函数的操作决定生命周期

    Point& Protset3(int a){
        Point temp(a, a);
        return temp;
        //执行 return temp;不会产生匿名对象,而是会将temp的地址先赋值到引用中,
        //在释放temp的内存,此时Point&得到是一个脏数据
    }

    void PrintfA()const{
        cout << "x="<<x << endl;
        cout << "y=" << y << endl;
    }

private:
    int x;
    int y;
};


void ProtectA(){
    //生成一个匿名对象,因为用来初始化另一个同类型的对象,这个匿名对象会直接转换成新的对象,
    //减少资源消耗
    Point p1 = Point(1,1);
    /*Point p2(2, 2);
    p2 = p1.Protset(3);
    p2.PrintfA();*/
    //观察发现p2打印出正确数据,因此得出结论p1.Protset(3);返回来一个匿名对象,
    //但是这个匿名对象执行完"="之后,才会被释放
    Point p4(5, 5);
    p4=p1.Protset2(4);
    p4.PrintfA();
}

void main(){
    ProtectA();
    system("pause");
}
1. 1+2+3+...+n ,要求不能使用乘除法、 for while if else switch case 等关键字及条件判
断语句( A?B:C
class Solution {
public:
    int Sum_Solution(int n) {
        //通过与运算判断n是否为正数,以结束递归
        n && (n += Sum_Solution(n - 1)); 
        return n;
    }
};
class Solution {
  public:

    class sum {
      public:
        sum() {
            m_sum += m_i;
            m_i++;
        }
    };
    int Sum_Solution(int n) {
    m_i=1;
    sum obj[n];//调用拷贝构造函数n次
    return m_sum;
    }
    static int m_i;
    static int m_sum;
};

int Solution::m_i = 0;
int Solution::m_sum = 0;

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值