栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > C/C++/C#

c++学习(2)类

C/C++/C# 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

c++学习(2)类

对于类的学习
  • 类
    • 类定义
    • 构造函数与析构函数
      • 构造函数
      • 析构函数
    • this指针
    • 使用const意义
    • 运算符重载
    • 友元函数
    • 技巧1
    • 类的自动转换和强制类型转换
      • 类的自动转换
      • 类的反转换
  • 类和动态内存分配
    • 特殊成员函数
      • 默认构造函数
      • 复制构造函数

类 类定义

面向对象编程(OOP)是一种特殊的、设计程序的概念方法,c++通过一些特征改进了c语言,使得这些方法更容易(抽象、封装和书籍隐藏、多态、继承、代码的可重用性)。一般定义类名时会将第一个首字母大写

class Merge {//创建类
public://共有成员,对象可以直接访问
	int input(int num);//类方法源函数
private://私有成员,类方法可以访问
	int num;//私有成员变量。
};
int Merge::input(){return 0;}//类方法定义
int main(){
Merge mer;//定义对象
mer::input();//::调用类的公共方法,每个对象都有一个属于自己的存储空间,但是同一个类的所有对象都共享同一组类方法,
return 0;
}

一个类就相当于一个命名空间(类存在友函数),调用类中的函数,使用也是与调用命名空间相识。

构造函数与析构函数 构造函数

构造函数与类名同名,程序声明对象时,将自动调用构造函数,通常会用来对于对象进行初始化,因为类不同于构造函数可以直接初始化,在类中存在五法直接访问的隐藏数据,需要使用内部的函数对对象进行初始化。

class Stock{
Stock(int n);//构造函数源函数
}
Stock::Stock(int n){}//构造函数定义
int main(){
Stock st1(666);//调用方法1
Stock st2=Stock(666);//调用方法2

Stock * pst= new Stock(666);//将构造函数与new一起使用。
return 0;
}

构造函数有两种调用方法,第一种是隐式的调用,第二种是显式的调用。
定义构造函数时添加默认值Stock(int n =1);或进行函重载Stock()

析构函数

析构函数原型必须是~Stock()不能带有任何参数,其在对象结束时将会被调用,定义Stock::~Stock(),通常被用于对象中,有使用new时调用delete对内存进行释放。

this指针

当需要对两个对象的成员变量做比较时,可以使用,用变量接收一个带有返回值的成员函数,另外可以使用this的方法返回对象;

cons Stock&Stock::topval(const Stock &s)const{
	if(s.n>n)
		return s;
	else
		return *this;
}
使用const意义

几个要注意的点

  1. 对于加在成员函数后的const,表示的是该函数不可以修改对象的成员变量。
    加在非成员函数或静态成员后将会产生报错。
    例外是对于mutable修饰的成,员加了const的成员函数,可以被非cosnt对象和const对象调用,但是不加const的成员函数只能被非const对象调用。
    char getData()const{return this->letter;}
  2. 每个成员函数都有一个this指针。this指针指向调用对象。要返回的不是this,因为this是对象的地址,而不是对象本身,所以返回*this。
    在函数后加const限定符将this限定为const,这样不能使用this来修改对象的值。
运算符重载

operator (运算符) ()可以对运算符进行重载。
下面样例:对传入的两个时间进行想加。

class Time {//创建时间类
public:
	Time();
	Time(int h,int m);
	Time sum(Time & s);//普通方法形式
	Time operator + (Time& s);//运算符重载
	void show();
private:
	int hours;//小时
	int minutes;//分钟
};

Time Time::sum(Time& s) {//定义
	Time sum;
	sum.minutes = s.minutes + this->minutes;
	sum.hours = s.hours + this->hours + sum.minutes/60;
	sum.minutes = sum.minutes % 60;
	return sum;
}
Time Time::operator+(Time& s) {//与sum定义完全相同
	Time sum;
	sum.minutes = s.minutes + this->minutes;
	sum.hours = s.hours + this->hours + sum.minutes / 60;
	sum.minutes = sum.minutes % 60;
	return sum;
}
Time::Time() {
	this->hours = 0;
	this->minutes = 0;
}
Time::Time(int h_, int m_) {
	this->hours = h_;
	this->minutes = m_;
}
void Time::show() {
	std::cout << this->hours<<":" << this->minutes << std::endl;
}
int main(){
Time a1{ 1,1 };
Time a2{ 1,2 };
a1.sum(a2).show();
a1.operator+(a2).show();
(a1+a2).show();
//输出
//3:10
//3:10
//3:10
return 0;}

使用operator重载函数后可以对对象直接使用加号运算符,就能够达到调用sum()函数的效果。

友元函数

创建友元函数需要在类中声明,并在原型申明前面加上关键字friend。虽然其在内部声明但是其并不可以使用成员运算符来调用。它有成员函数相同的访问权限。

friend Time operator * (int n,const Time &t);//原型
Time operator * (int n,const Time &t){}//定义
Time temp = n*a1
temp = operator*(n,a1);

友元函数在定义时不需要加friend也不能使用Time::限定符。

对于<<运算符重载,添加友元函数使得std::cout能够直接的输出Time对象。

class Time {//创建时间类
public:
	Time();
	Time(int h,int m);
	void show();
	friend std::ostream & operator <<(std::ostream& os, const Time& t);
private:
	int hours;//小时
	int minutes;//分钟
};
Time::Time() {
	this->hours = 0;
	this->minutes = 0;
}
Time::Time(int h_, int m_) {
	this->hours = h_;
	this->minutes = m_;
}
void Time::show() {
	std::cout << this->hours<<":" << this->minutes << std::endl;
}
std::ostream & operator <<(std::ostream& os, const Time & t) {
	os << t.hours << "hours," << t.minutes << "minutes" << std::endl;
	return os;
}
int main(){
Time a1{ 1,1 };
Time a2{ 1,2 };
std::cout << (a1 + a2)<<777< 

注意在对<<重载时返回值是引用,os对象是引用进函数的,同样也可以引用出去。同时如果不这样做,那么后面<<777将无法正确的输出。
输出2是输出1的调用展示。运算符的重载调用的是

技巧1

使用全局的算数符重载,弥补类中算数符重载遇到的问题(n*对象无法解析),

class Stock {
public:
	Stock();
	Stock(int n);
	Stock operator*(double n);
	void show();
private:
	int a;
};
Stock::Stock() {
	this->a = 0;
}
Stock::Stock(int n) {
	this->a = n;
}
Stock Stock::operator*(double n) {

	this->a *= n;
	return *this;
}
void Stock::show() {
	std::cout << this->a;
}
Stock operator*(double n, Stock& o) { //全局函数使用去全局函数重载*,将其重载给Stock的成员函数
	return o * n;
}
int main(){
Stock a1{ 1 };
a1 = a1 * 6;
a1 = 6.0 * a1;
a1.show();
return 0;
}
//输出
//36

使用全局的运算符重载使得,将Stock成员函数不能调用的a1=6.0*a1,转化为成员函数能够调用的格式;

类的自动转换和强制类型转换

在C++98中只可以在构造函数前,加explicit使其变为强制类型。
才C++11中可以在转换函数钱,加explicit使其变为强制类型。
应谨慎的使用隐式转换类型,通常,最好选择使用在被显示调用时才会执行的函数。

类的自动转换

与定义的构造函数相关
将对象Stock初始化为doublel类型时。
将double值赋值给Stock对象时
将double值传递给接收

class Stock{
public:
	Stock(double n);
};
类的反转换

与定义的转换函数有关
将类转换为特定的类型。
转换函数的格式:
peratortypename();
转换函数必须是类方法,不能指定返回类型,不能有参数。

class Stock{
public:
	Stock();
	Stock(int n);
	operator double();
private:
	int a;
};	
Stock::Stock(){this->a=0;}
Stock::Stock(int n){this->a=n;}
Stock::operator double(){
return int(this->a);
} 
int main(){
Stock a1(1);
std::cout< 

在main函数中的输出是允许的,因为Stock类只有一个类型转换函数operator double()。

类和动态内存分配 特殊成员函数

C++98自动提供的成员函数

  1. 默认构造函数,如果没有定义构造函数;
  2. 默认解析函数,如果没有定义解析函数;
  3. 复制构造函数,如果没有定义;
  4. 赋值运算符,如果没有定义;
  5. 地址运算符,如果没有定义;

C++11额外提供了

  1. 移动构造函数;
  2. 移动赋值函数;
//创建拟string
class StringBad {
private:
	char* str;
	int len;
	static int num_strings;
public:
	StringBad();
	StringBad(const char*s);
	~StringBad();
	friend std::ostream& operator <<(std::ostream& os, const StringBad& st);
};
//创建拟string
int StringBad::num_strings = 0;
StringBad::StringBad() {
	this->len = 4;
	this->str = new char[len + 1];
	this->num_strings++;
}
StringBad::StringBad(const char * s) {
	this->len = std::strlen(s);
	this->str = new char[len + 1];
	std::strcpy(this->str, s);
	this->num_strings++;
}
StringBad::~StringBad() {
	--this->num_strings;
	delete[] str;
}
std::ostream& operator << (std::ostream& os, const StringBad& st) {
	os << st.str;
	return os;
}
//全局函数
int md1(const StringBad s){}
int md2(const StringBad & s){}
int main(){
	StringBad a1;
	md2(a1);	
	std::cout< 
  1. 这些都是因为,复制函数和赋值运算符使用默认值引起的。
  2. 要注意对于static进行初始化(int StringBad::num_strings = 0;),否则将会弹出引用外部符号的报错。使用static限制符,变量会变成所有类对象共享的。
默认构造函数
ClassName(){};
Ikun(){};
Ikun(){Ikun_ct=0;};
Ikun(int n=0){Ikun_ct=n;};
复制构造函数
ClassNaem(const ClassName &)
Ikun(const Ikun &);
//下面四种情况将会调用复制构造函数
Ikun ditto(motto);
Ikun metto = motto;
Ikun also = Ikun(motto);
Ikun * pIkun = new Ikun(motto);
转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/1033030.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号