类和对象:
1.声明类
class Human
{
// Member attributes:
string name;
string dateOfBirth;
string placeOfBirth;
string gender;
// Member functions:
void Talk(string textToTalk);
void IntroduceSelf();
...
};
我们也可以使用new来为对象动态的申请内存。
Human* firstWoman = new Human(); // dynamically allocated Human
delete firstWoman; // de-allocating memory
注:即Human是申明的类,其firstWoman是对象
firstMan.dateOfBirth = "1970";
firstMan.IntroduceSelf();
如果有一个指针 firstWoman,它指向 Human 类的一个实例,则可使用指针运算符(->)来访问成员(这将在下一小节介绍),也可使用间接运算符(*)来获取对象,再使用句点运算符来访问成员:
Human* firstWoman = new Human();
(*firstWoman).IntroduceSelf();
总的来说和结构体长得差不多的,目前而言。
关键字:public和private
样例(没有默认构造函数的类):
#include<iostream>
#include<string>
#include<algorithm>
#include<vector>
using namespace std;
class Human {
private:
int age;
string name;
public:
int GetAge(){
return age;
}
void SetAge(int humansAge){
if(humansAge>0)
age=humansAge;
//避免被设置为0
}
};
int main(void) {
Human eve;
eve.SetAge(16);
cout<<eve.GetAge();
//cout<<eve.age //don't be allowed
return 0;
}
同样,我们可以简单更改程序,使得其输出更小的年龄。
之所以我们可以达成这一目的,是由于age被声明在private中,不能直接访问它,只能通过GetAge方法进行访问。
在面向对象编程语言中,抽象是一个非常重要的概念,让程序员能够决定哪些属性只能让类及其成员知道,类外的任何人都不能访问( 友元除外 )
构造函数:
1.声明和实现构造函数
似于下面这样:
class Human
{
public:
Human(); // declaration of a constructor
};
码类似于下面这样:
class Human
{
public:
Human()
{
// constructor code here
}
};
在类声明外定义构造函数的代码类似于下面这样:
class Human
{
public:
Human(); // constructor declaration
};
// constructor implementation (definition)
Human::Human()
{
// constructor code here
}
注::被称为作用域解析运算符。例如,Human::dateOfBirth 指的是在 Human 类中声明的变量 dateOfBirth ,而 ::dateOfBirth 表示全局作用域中的变量 dateOfBirth 。
何时,如何使用构造函数及重载构造函数:
构造函数的使用代码举例:
#include<iostream>
#include<string>
using namespace std;
class Human {
private:
int age;//init 0
string name;
public:
Human(){
age=0;
cout<< "Default constructor: name and age not set."<<endl;
}
Human(string humansName,int humansAge){
name=humansName;
age=humansAge;
cout<< "Overloaded constructor creates ";
cout<<name<<" of "<<age<<" years."<<endl;
}
};
int main(void) {
Human firstMan;
Human firstWoman("ZHY",16);
return 0;
}
Human(){
age=0;
cout<< "Default constructor: name and age not set."<<endl;
}
带有默认值的构造函数:
class Human
{
private:
string name;
int age;
public:
// overloaded constructor (no default constructor)
Human(string humansName, int humansAge = 25)
{
name = humansName;
age = humansAge;
cout << "Overloaded constructor creates " << name;
cout << " of age " << age << endl;
}
// ... other members
};
Human adam("Adam"); // adam.age is assigned a default value 25
Human eve("Eve", 18); // eve.age is assigned 18 as specified
注意:
class Human
{
private:
string name;
int age;
public:
// default values for both parameters
Human(string humansName = "Adam", int humansAge
= 25)
{
name = humansName;
age = humansAge;
cout << "Overloaded constructor creates ";
cout << name << " of age " << age;
}
};
buffer:n. 缓冲物,起缓冲作用的人;缓冲器;缓存区;老糊涂 v. 保护,保障;缓存
析构函数:
在对象被销毁时自动调用,释放内存(在main函数之后)。
当然,析构函数还是比较困难的,在我们学习的初期,先对它进行了解即可,而无需深研。
class Human
{
~Human(); // declaration of a destructor
};
在类中:
class Human
{
public:
~Human()
{
// destructor code here
}
};
在类外:
class Human
{
public:
~Human(); // destructor declaration
};
// destructor definition (implementation)
Human::~Human()
{
// destructor code here
}
何时及如何使用析构函数
注:
腭化符号(~):main函数运行结束后,令之自动调用。
放松时刻:
#include<iostream>
#include<string>
using namespace std;
class Human {
private:
int age;//init 0
string name;
public:
Human(string humansName="Adam",int humansAge=25)
:name(humansName),age(humansAge)
{
// name=humansName;
// age=humansAge;
cout<< "Overloaded constructor creates ";
cout<<name<<" of "<<age<<" years."<<endl;
}
~Human(){
cout<<"我啥也没做,哈哈哈"<<endl;
}
};
int main(void) {
Human adam;
Human firstWoman("ZHY",16);
cout<<"-------end of main------"<<endl;
return 0;
}
continue:
复制构造函数:
浅复制带来的问题:
分析:
使用复制构造函数确保深复制
//深复制的代码
好了,我没写 ,原因如下:
寄,太难了,看不懂了,构造函数和析构函数的其他用途就不写了,蒟蒻感juo无能为力了。
往下走
this 指针
class Human
{
private:
void Talk (string Statement)
{
cout << Statement;
}
public:
void IntroduceSelf()
{
Talk("Bla bla"); // same as Talk(this, "Bla Bla")
}
};
void SetAge(int humansAge)
{
this->age = humansAge; // same as age = humansAge
}
将 sizeof( )用于类
结构和类的不同之处:
Human的struct实现:
struct Human
{
// constructor, public by default (as no access specified is mentioned)
Human(const MyString& humansName, int humansAge, bool humansGender)
: name(humansName), age (humansAge), Gender(humansGender) {}
int GetAge ()
{
return age;
}
private:
int age;
bool gender;
MyString name;
};
正如您看到的,结构 Human 与类 Human 很像;结构的实例化与类的实例化也很像:
Human firstMan("Adam", 25, true); // an instance of struct Human
声明友元
样例代码:
#include<iostream>
#include<string>
using namespace std;
class Human {
private:
friend class Utility;
int age;//init 0
string name;
public:
Human(string humansName = "Adam", int humansAge = 25)
: name(humansName), age(humansAge) {
// name=humansName;
// age=humansAge;
}
};
class Utility {
public:
static void DisplayAge(const Human& person) {
cout << person.age << endl;
}
};
int main(void) {
Human firstMan("Adam", 25);
cout << "Accessing private member age via friend class: ";
Utility::DisplayAge(firstMan);
//Utility这个类没有对象,所以我们直接使用它的DisplayAge函数
return 0;
}
friend class Utility;
共用体:一种特殊的数据存储机制
共用体是一种特殊的类,每次只有一个非静态数据成员处于活动状态。因此,共用体与类一样,可包含多个数据成员, 但不同的是只能使用其中的一个 。
1.声明共用体
union UnionName
{
Type1 member1;
Type2 member2;
…
TypeN memberN;
};
实例化:
UnionName unionObject;
unionObject.member2 = value; // choose member2 as the active member
注:
2.何时使用共用体:
enum和switch-case一起用。
对类和结构使用聚合初始化
例1:
int myNums[] = { 9, 5, -1 }; // myNums is int[3]
char hello[6] = { 'h', 'e', 'l', 'l', 'o', ' \0' };
例2:
struct Aggregate1
{
int num;
double pi;
};
//可将其作为一个整体进行初始化
Aggregate1 a1{ 2017, 3.14 };
struct Aggregate2
{
int num;
char hello[6];
int impYears[5];
};
//对于这个结构,可像下面这样进行初始化:
Aggregate2 a2 {42, {'h', 'e', 'l', 'l', 'o'}, {1998, 2003, 2011, 2014, 2017}};
问:总是应该编写一个复制构造函数吗?答: 如果类的数据成员是设计良好的智能指针、字符串类或 STL 容器(如 std::vector ),则编译器生成的默认复制构造函数将调用成员的复制构造函数。然而,如果类包含原始指针成员(如使用 int*而不是 std::vector<int> 表示的动态数组),则需要提供设计良好的复制构造函数,确保将类对象按值传递给函数时进行深复制,创建该数组的拷贝。
问:在复制构造函数中,为何将指向源对象的引用作为参数?答: 这是编译器对复制构造函数的要求。其原因是,如果按值接受源对象,复制构造函数将调用自己,导致没完没了的复制循环。
今天结束了,寄几寄~~~