c++一些入门基础,也是初学者容易卡住的地方
2017-10-09 11:31
417 查看
一:类和对象:
不说那么多官方概念,我认为类就是更高级于c语言的结构体。
因为它具有封装性,那么什么是封装?简单来说,类里不仅可以有变量,还可以有函数。
不过这个类是声明,不占空间,,像一个模型一样的东西,那么对象就是类的实例化!
我举个例子,如果会弹琴的朋友肯定知道看曲谱和真正弹奏的区别,那么类就是一个谱子,一个谱子可以弹奏多首曲子。
对象就是它的实例化,也就是弹出来这首曲子,曲子里有很多不同的音符,节奏,段落。
题外话:我副职业指弹吉他
以上是我个人的观点,觉得比较好理解,如果不对欢迎大神来更正。
刚才我说,c++更高级,他当然不是仅仅高级在类里可以写函数,还有很多东西需要慢慢学习。
.访问限定符:
那么来定义一个简单的类:
class Date
{
public:
void show()
{
cout<<_year<<"-"<<_month<<"-"<<_day<<endl;
}
public:
int _year;
int _month;
int _day;
};
int main()
{
Date d1;//类实例化出对象
d1._year = 2017;
d1._month = 10;
d1._day = 9;
d1.show();
return 0;
}
通过sizeof(d1);得到d1的大小是12,它遵守内存对齐,那么难道成员函数不占空间吗?
注:空类的大小是1个字节,不是0,表示它存在,站位。
二:隐含的this指针:
1.每个成员函数(除了构造函数)都有一个指针形参,叫this,是隐含的。
2.在对象调用成员函数时,对象的地址作实参传递给成员函数的第一个指针形参。
三:默认成员函数:
1.构造函数:
无返回值
函数值与类名相同
对象实例化自动调用
可重载
如不定义,自动生成一个缺省的构造函数
无参,全缺省都认为是缺省构造函数,缺省的只能有一个。
class Date
{
public:
//Date()//无参
//{
//
//}
//Date(int year,int month,int day)//带参
//{
// this->_year = year;
// this->_month = month;
// this->_day = day;
// cout<<_year<<"-"<<_month<<"-"<<_day<<endl;
//}
Date(int year = 2017,int month = 10,int day = 9)//缺省
{
this->_year = year;
this->_month = month;
this->_day = day;
cout<<_year<<"-"<<_month<<"-"<<_day<<endl;
}
void show()
{
cout<<_year<<"-"<<_month<<"-"<<_day<<endl;
}
private:
int _year;
int _month;
int _day;
};
int main()
{
Date d1(2017,10,1);
Date d2;
return 0;
}
d1后面得加括号,d2后面不能加,因为有可能被识别为其他函数。
2.拷贝构造函数:创建对象是用同类对象来初始化。
Date(const Date& d)
{
this->_year = d._year;
this->_month = d._month;
this->_day = d._day;
}定义了拷贝构造函数之后,
Date d1(2017,10,1);
Date d2(d2);//d2就和d1一样了。
d2的地址传给this,d1引用传递,否则会无穷递归,如图。
注意:必须用引用传参,不引用就会无穷递归,给d1加const。
如果未定义拷贝构造函数,会默认为值拷贝。(值拷贝有时候会有问题,比如有指针指向动态内存开辟的空间,如下)
3.析构函数:当一个对象生命周期结束,调用的成员函数,是清理工作。
类名前加~
无参数无返回值
一个类只有一个析构,未定义会自动生成缺省的
对象生命周期结束,自动调用。
接下来我写一个有指针指向动态内存开辟的空间。
class Seqlist
{
public:
Seqlist()
{
_a = (int*)malloc(sizeof(int)*5);
_size = 0;
_capacity = 5;
}
void PushBack(int x)
{
this->_a[(this->_size)++] = x;
}
void print()
{
for(size_t i = 0; i < this->_size; i++)
{
cout<<this->_a[i]<<endl;
}
}
Seqlist(const Seqlist& s)
{
int i = 0;
for(i = 0; i<s._size; i++)
{
this->_a[i] = s._a[i];
}
}
~Seqlist()
{
if(this->_a)
{
free(this->_a);
this->_a = NULL;
this->_size = 0;
this->_capacity = 0;
}
}
private:
int* _a;
size_t _size;
size_t _capacity;
};
int main()
{
Seqlist s1;
s1.PushBack(1);
s1.PushBack(2);
s1.PushBack(3);
s1.PushBack(4);
s1.print();
Seqlist s2 = s1;
s2.print();
}
显然这是一个简单的顺序表,实现了尾插的功能。
析构函数最后free掉了_a,并且把它指向NULL,看起来都没有问题,不过如果不写拷贝构造函数,而直接使用的话,会出现问题。
4.运算符重载:为了让自定义类型可以用运算符
operator+合法的运算符构成函数名。
注:c++5个不支持重载的运算符: .* :: sizeof ?: .
举例:operator<
class Date
{
public:
Date(int year = 2017,int month = 10,int day = 9)
{
_year = year;
_month = month;
_day = day;
cout<<_year<<"-"<<_month<<"-"<<_day<<endl;
}
bool operator<(const Date& d)
{
if(this->_year < d._year)
{
return true;
}
else if(this->_year == d._year)
{
if(this->_month < d._month)
{
return true;
}
else if(this->_month == d._month)
{
if(this->_day < d._day)
{
return true;
}
}
}
return false;
}
private:
int _year;
int _month;
int _day;
};
void test()
{
Date d1(2017,1,25);
Date d2(2017,1,27);
cout<<(d1<d2)<<endl;
}
int main()
{
test();
return 0;
}
将它写入类内当成成员函数,不然访问不了私有成员。
d1<d2,其实就是d1.operator(&d1,d2),d1的地址传给this,d2引用传递。
赋值运算符重载:
class Date
{
public:
Date(int year = 2017,int month = 10,int day = 9)
{
_year = year;
_month = month;
_day = day;
//cout<<_year<<"-"<<_month<<"-"<<_day<<endl;
}
Date& operator=(const Date& d)
{
if(this != &d)
{
_year = d._year;
_month = d._month;
_day = d._day;
}
return *this;
}
void show()
{
cout<<_year<<"-"<<_month<<"-"<<_day<<endl;
}
private:
int _year;
int _month;
int _day;
};
void test()
{
Date d1(2017,1,25);
Date d2(2017,1,27);
d2 = d1;
d2.show();
}
int main()
{
test();
return 0;
}
注:引用返回是为了能够连续赋值,比如:d1 = d2 =d3;
if是为了避免两日期相同还赋值浪费时间。
拷贝构造和赋值运算符重载的区别:
Date d4 = d3;//拷贝构造,用同类对象来创建。
d4 = d3;//赋值运算符重载,已存在的两对象。
不说那么多官方概念,我认为类就是更高级于c语言的结构体。
因为它具有封装性,那么什么是封装?简单来说,类里不仅可以有变量,还可以有函数。
不过这个类是声明,不占空间,,像一个模型一样的东西,那么对象就是类的实例化!
我举个例子,如果会弹琴的朋友肯定知道看曲谱和真正弹奏的区别,那么类就是一个谱子,一个谱子可以弹奏多首曲子。
对象就是它的实例化,也就是弹出来这首曲子,曲子里有很多不同的音符,节奏,段落。
题外话:我副职业指弹吉他
以上是我个人的观点,觉得比较好理解,如果不对欢迎大神来更正。
刚才我说,c++更高级,他当然不是仅仅高级在类里可以写函数,还有很多东西需要慢慢学习。
.访问限定符:
那么来定义一个简单的类:
class Date
{
public:
void show()
{
cout<<_year<<"-"<<_month<<"-"<<_day<<endl;
}
public:
int _year;
int _month;
int _day;
};
int main()
{
Date d1;//类实例化出对象
d1._year = 2017;
d1._month = 10;
d1._day = 9;
d1.show();
return 0;
}
通过sizeof(d1);得到d1的大小是12,它遵守内存对齐,那么难道成员函数不占空间吗?
注:空类的大小是1个字节,不是0,表示它存在,站位。
二:隐含的this指针:
1.每个成员函数(除了构造函数)都有一个指针形参,叫this,是隐含的。
2.在对象调用成员函数时,对象的地址作实参传递给成员函数的第一个指针形参。
三:默认成员函数:
1.构造函数:
无返回值
函数值与类名相同
对象实例化自动调用
可重载
如不定义,自动生成一个缺省的构造函数
无参,全缺省都认为是缺省构造函数,缺省的只能有一个。
class Date
{
public:
//Date()//无参
//{
//
//}
//Date(int year,int month,int day)//带参
//{
// this->_year = year;
// this->_month = month;
// this->_day = day;
// cout<<_year<<"-"<<_month<<"-"<<_day<<endl;
//}
Date(int year = 2017,int month = 10,int day = 9)//缺省
{
this->_year = year;
this->_month = month;
this->_day = day;
cout<<_year<<"-"<<_month<<"-"<<_day<<endl;
}
void show()
{
cout<<_year<<"-"<<_month<<"-"<<_day<<endl;
}
private:
int _year;
int _month;
int _day;
};
int main()
{
Date d1(2017,10,1);
Date d2;
return 0;
}
d1后面得加括号,d2后面不能加,因为有可能被识别为其他函数。
2.拷贝构造函数:创建对象是用同类对象来初始化。
Date(const Date& d)
{
this->_year = d._year;
this->_month = d._month;
this->_day = d._day;
}定义了拷贝构造函数之后,
Date d1(2017,10,1);
Date d2(d2);//d2就和d1一样了。
d2的地址传给this,d1引用传递,否则会无穷递归,如图。
注意:必须用引用传参,不引用就会无穷递归,给d1加const。
如果未定义拷贝构造函数,会默认为值拷贝。(值拷贝有时候会有问题,比如有指针指向动态内存开辟的空间,如下)
3.析构函数:当一个对象生命周期结束,调用的成员函数,是清理工作。
类名前加~
无参数无返回值
一个类只有一个析构,未定义会自动生成缺省的
对象生命周期结束,自动调用。
接下来我写一个有指针指向动态内存开辟的空间。
class Seqlist
{
public:
Seqlist()
{
_a = (int*)malloc(sizeof(int)*5);
_size = 0;
_capacity = 5;
}
void PushBack(int x)
{
this->_a[(this->_size)++] = x;
}
void print()
{
for(size_t i = 0; i < this->_size; i++)
{
cout<<this->_a[i]<<endl;
}
}
Seqlist(const Seqlist& s)
{
int i = 0;
for(i = 0; i<s._size; i++)
{
this->_a[i] = s._a[i];
}
}
~Seqlist()
{
if(this->_a)
{
free(this->_a);
this->_a = NULL;
this->_size = 0;
this->_capacity = 0;
}
}
private:
int* _a;
size_t _size;
size_t _capacity;
};
int main()
{
Seqlist s1;
s1.PushBack(1);
s1.PushBack(2);
s1.PushBack(3);
s1.PushBack(4);
s1.print();
Seqlist s2 = s1;
s2.print();
}
显然这是一个简单的顺序表,实现了尾插的功能。
析构函数最后free掉了_a,并且把它指向NULL,看起来都没有问题,不过如果不写拷贝构造函数,而直接使用的话,会出现问题。
4.运算符重载:为了让自定义类型可以用运算符
operator+合法的运算符构成函数名。
注:c++5个不支持重载的运算符: .* :: sizeof ?: .
举例:operator<
class Date
{
public:
Date(int year = 2017,int month = 10,int day = 9)
{
_year = year;
_month = month;
_day = day;
cout<<_year<<"-"<<_month<<"-"<<_day<<endl;
}
bool operator<(const Date& d)
{
if(this->_year < d._year)
{
return true;
}
else if(this->_year == d._year)
{
if(this->_month < d._month)
{
return true;
}
else if(this->_month == d._month)
{
if(this->_day < d._day)
{
return true;
}
}
}
return false;
}
private:
int _year;
int _month;
int _day;
};
void test()
{
Date d1(2017,1,25);
Date d2(2017,1,27);
cout<<(d1<d2)<<endl;
}
int main()
{
test();
return 0;
}
将它写入类内当成成员函数,不然访问不了私有成员。
d1<d2,其实就是d1.operator(&d1,d2),d1的地址传给this,d2引用传递。
赋值运算符重载:
class Date
{
public:
Date(int year = 2017,int month = 10,int day = 9)
{
_year = year;
_month = month;
_day = day;
//cout<<_year<<"-"<<_month<<"-"<<_day<<endl;
}
Date& operator=(const Date& d)
{
if(this != &d)
{
_year = d._year;
_month = d._month;
_day = d._day;
}
return *this;
}
void show()
{
cout<<_year<<"-"<<_month<<"-"<<_day<<endl;
}
private:
int _year;
int _month;
int _day;
};
void test()
{
Date d1(2017,1,25);
Date d2(2017,1,27);
d2 = d1;
d2.show();
}
int main()
{
test();
return 0;
}
注:引用返回是为了能够连续赋值,比如:d1 = d2 =d3;
if是为了避免两日期相同还赋值浪费时间。
拷贝构造和赋值运算符重载的区别:
Date d4 = d3;//拷贝构造,用同类对象来创建。
d4 = d3;//赋值运算符重载,已存在的两对象。
相关文章推荐
- c++的一些容易混淆基础知识点
- Java入门:一些初学者需要掌握的基础算法程序——二分查找
- Java入门:一些初学者需要掌握的基础算法程序——逆序输出
- private:c/c++ 我的一些容易出错的地方 =>持续更新
- 自己总结C/C++的一些容易被遗忘的基础知识!
- C++基础入门教程(七):一些比较特别的基础语法总结
- 【网站设计入门】网站设计初学者应该注意哪些基础问题?(二)
- C++ STL编程轻松入门基础
- 初学者必备:C++经典入门详细教程
- C++基础(一些经常混淆的概念)
- C++ STL编程轻松入门基础
- 一些容易被初学者忽视的C#语言细节
- Struts1.0学习文档--初学者入门的地方
- Button、EditText控件的一些容易忽略的好用的地方
- 一些好的C\C++基础 博客
- C/C++基础到高级入门到精通的学习…
- 复合控件与事件(1)——基础入门,组合也是一种封装
- qt入门--一些基础控件的应用
- OC中的一些基础知识,不对的地方还请指正!
- C++入门教程:C++基础教程,含进阶