以下是本人时隔一段时间再次复习c++基本语法的笔记。学过的知识时间久了就容易忘记。隔一段时间进行回顾。
一)复制构造函数
1、复制构造函数的参数是本类对象的引用
类名(const 类名& 引用名);
如:类内Student(const Student& );
类外:Student::Student(const Student& stu)
{
int len=strlen(stu.name)+1;
name=new char[len];
strcpy(name,stu.name);
age=stu.age;
cout<<"Student(const Student& )"<<endl;
}
使用const的原因是为了防止被引用的对象被改变。
关于const这个关键字:
const关键字的作用
(1)作用:
1)欲阻止一个变量被改变,可使用const,在定义该const变量时,需先初始化,以后就没有机会改变他了;
2)对指针而言,可以指定指针本身为const,也可以指定指针所指的数据为const,或二者同时指定为const;
3)在一个函数声明中,const可以修饰形参表明他是一个输入参数,在函数内部不可以改变其值;
4)对于类的成员函数,有时候必须指定其为const类型,表明其是一个常函数,不能修改类的成员变量;
5)对于类的成员函数,有时候必须指定其返回值为const类型,以使得其返回值不为“左值”。
const修饰变量
变量的值不能改变
const修饰指针
如果const位于*的左侧,则const就是用来修饰指针所指向的变量,即指针指向为常量
如果const位于*的右侧,const就是修饰指针本身,即指针本身是常量
指针常量:不能通过指针来修改变量的值。
常量指针:一直指向该变量,不能给该指针赋予其他地址
函数中使用const
const修饰函数参数
表示参数不可变
若参数为引用,可以增加效率
const引用传递和函数按值传递的效果是一样的,但按值传递会先建立一个类对象的副本, 然后传递过去,而它直接传递地址,所以这种传递比按值传递更有效
const按值传递时只是外部对象的拷贝,值的改变不会对外部有什么影响,那么是不是没有什么意义:错,重要的目的就是告诉说这个变量不允许被修改,传引用效率会高一点而已。
const 修饰函数返回值
含义和const修饰变量和指针的含义相同
类中使用const
const修饰成员变量
表示成员变量不能被修改,同时只能在初始化列表中赋值
const修饰成员函数
该函数不能改变对象的成员变量
不能调用非const成员函数,因为任何非const成员函数会有修改成员变量的企图
const的成员函数才能被一个const类对象调用。即const类对象只能调用const成员函数
const关键字不能与static关键字同时使用,因为static关键字修饰静态成员函数,静态成员函数不含有this指针,即不能实例化,const成员函数必须具体到某一实例。
const修饰类对象
对象的任何成员都不能被修改
只能调用const成员函数
二)new,是C++提供的用于动态申请存储空间的运算符。
new开辟的空间在堆上,而一般声明的变量存放在栈上。new的使用格式,new出来的是一段空间的首地址。所以一般需要用指针来存放这段地址。
注意以下的区别:
int *p = new int(10);//申请了一个初值为10的整型数据
int *arr = new int[10];//申请了能存放10个整型数据元素的数组,其首地址为arr
delete p; delete[] arr;//注意要删除数组时,需要加[],以表示arr为数组。
int example1()
{
//可以在new后面直接赋值
int *p = new int(3);
//也可以单独赋值
//*p = 3;
//如果不想使用指针,可以定义一个变量,在new之前用“*”表示new出来的内容
int q = *new int;
q = 1;
cout << q << endl;
return *p;
}
三)this关键字
在C++里面,每一个对象都能通过this指针来访问自己的地址。this是所有成员函数的隐藏参数。
在C++中,当成员函数中某个变量与成员变量名字相同,则使用this关键字来表示成员变量。或者,需要返回类变量或者结构体变量的时候,使用this关键字。
四)友元
有时需要定义一些函数,这些函数不是类的一部分,但又需要频繁地访问类的数据成员,这时可以将这些函数定义为该函数的友元函数。除了友元函数外,还有友元类,两者统称为友元。友元的作用是提高了程序的运行效率(即减少了类型检查和安全性检查等都需要时间开销),但它破坏了类的封装性和隐藏性,使得非成员函数可以访问类的私有成员。
1.友元类:
友元类的所有成员函数都是另一个类的友元函数,都可以访问另一个类中的隐藏信息(包括私有成员和保护成员)。当希望一个类可以存取另一个类的私有成员时,可以将该类声明为另一类的友元类。定义友元类的语句格式如下:friend class 类名;friend和class是关键字,类名必须是程序中的一个已定义过的类。
例如,以下语句说明类B是类A的友元类:
class A
{
…
public:
friend class B;
…
};类B的所有成员函数都是类A的友元函数,能存取类A的私有成员和保护成员。
使用友元类时注意:
(1) 友元关系不能被继承。
(2) 友元关系是单向的,不具有交换性。若类B是类A的友元,类A不一定是类B的友元,要看在类中是否有相应的声明。
(3) 友元关系不具有传递性。若类B是类A的友元,类C是B的友元,类C不一定是类A的友元,同样要看类中是否有相应的申明
4.总结
友元类虽然好用,但是破坏了面向对象的封装特性。所以慎用
五)构造函数的另一种表示方法:
Time(int hour, int minute, int second):_hour(hour) , _minute(minute) , _second(second) {}表示给_hour赋值hour。依次类推
六)浅拷贝与深拷贝
释放内存一般在析构函数中运行。浅拷贝会把指针变量的地址复制,删除时会因出现删除两次而报错, 深拷贝会重新开辟内存空间。
class Test
{
private:
int* p;
public:
Test(int x)
{
this->p=new int(x);
cout << "对象被创建" << endl;
}
~Test()
{
if (p != NULL)
{
delete p;
}
cout << "对象被释放" << endl;
}
int getX() { return *p; }
//深拷贝(拷贝构造函数)
Test(const Test& a)
{
this->p = new int(*a.p);
cout << "对象被创建" << endl;
}
//浅拷贝(拷贝构造函数)
//Test(const Test& a)
//{
// this->p = a.p;
// cout << "对象被创建" << endl;
//}
};
int main()
{
Test a(10);
//我们手动的写拷贝构造函数,C++编译器会调用我们手动写的
Test b = a;
return 0;
}
七)static的作用
1):修饰全局变量时,表明一个全局变量只对定义在同一文件中的函数可见。
2):修饰局部变量时,表明该变量的值不会因为函数终止而丢失。
3):修饰函数时,表明该函数只在同一文件中调用。
4):修饰类的数据成员,表明对该类所有对象这个数据成员都只有一个实例。即该实例归 所有对象共有。
5):用static修饰不访问非静态数据成员的类成员函数。这意味着一个静态成员函数只能访问它的参数、类的静态数据成员和全局变量
八)静态局部变量
静态局部变量在程序执行到该对象的声明处就被首次初始化,以后函数的调用不再进行初始化(局部变量每次被调用总是被初始化)
九)
为什么静态成员函数不能申明为const
答:这是C++的规则,const修饰符用于表示函数不能修改成员变量的值,该函数必须是含有this指针的类成员函数,函数调用方式为thiscall,而类中的static函数本质上是全局函数,调用规约是__cdecl或__stdcall,不能用const来修饰它。<span style="line-height:26px">一个静态成员函数访问的值是其参数、静态数据成员和全局变量,而这些数据都不是对象状态的一部分。而对成员函数中使用关键字const是表明:函数不会修改该函数访问的目标对象的数据成员。既然一个静态成员函数根本不访问非静态数据成员,那么就没必要使用const了
为什么不能在类的内部定义以及初始化static成员变量,而必须要放到类的外部定义
答:
因为静态成员属于整个类,而不属于某个对象,如果在类内初始化,会导致每个对象都包含该静态成员,这是矛盾的。参考两篇博客:
https://blog.csdn.net/jiayi_yao/article/details/50998765 https://blog.csdn.net/sevenjoin/article/details/81772792
为什么要用得静态成员变量和静态成员函数
答:为了实现共享。因为静态成员函数和静态成员变量属于类,不属于类的实体,这样可以被多个对象所共享
静态成员函数与非静态成员函数的区别答:根本区别:静态成员函数不存在this指针,不能访问非静态成员变量。这篇博客总结的还不错静态成员函数与非静态成员函数的区别_独孤九戒的博客-CSDN博客_静态函数和非静态函数的区别
十)运算符重载
一.赋值运算符:函数名:operator + 运算符号
Date&(类名) operator=(const Date& d)
{
_year = d._year;
_month = d._month;
_day = d._day;
return *this;//返回需要赋值的对象本身
}
int main()
注意这里的返回值,因为最后是赋值给一个类,所以返回值也是类。但这样会使用一次拷贝构造,所以改为用引用,
{
Date d1;
Date d2 = d1;
return 0;
}返回值从Date,改为Date&
二.关系运算符.从例子中体会吧
bool Boy::operator>(const Boy &boy)
{
if (power() > boy.power())
{ return true; }
else { return false; }
}
bool Boy::operator<(const Boy &boy) {
if (power() < boy.power()) {
return true;
} else {
return false;
}
}
bool Boy::operator==(const Boy &boy) {
if (power() == boy.power()) {
return true;
} else {
return false;
}
三.算术运算符,从例子中体会吧
Pig Cow::operator+(const Sheep &sheep) {
// 牛肉 * 2 + // 羊肉 * 3
float ret = this->weigth * 2 + sheep.getWeigth() * 3;
// 返回前转换为Pig类型
return Pig(ret);
}
Pig Cow::operator+(const Cow &cow) {
// (牛 + 牛)* 2
float ret = (this->weigth + cow.weigth) * 2;
// 返回前转换为Pig类型
return Pig(ret);
}