一、面向对象程序设计的基本特点
二、类成员的访问控制
public
类外(main()函数)不能访问 private 和 protected 类型,只能访问声明 public 的对外接口
private
类开头若不加访问权限,则默认为private类型
可被基类的成员函数访问
可被基类的友元函数访问
protected
可被基类的成员函数访问
可被基类的友元函数访问
派生类的成员函数可以访问 当前对象 基类的protected成员
举例如下:
class A{
public: int c;
private: int b;
protected: int a;
};
class B: public A{
void func(){
c = 1; //right
b = 1; //wrong
a = 1; //right
B f;
f.a = 1 //wrong f是新构造的对象,不是func()面向的当前对象
}
}
int main(){
B boo;
A aoo;
aoo.b = 1 ; //worng
aoo.a = 1; //wrong
boo.b = 1; //wrong
boo.a = 1; //wrong
aoo.c = 1; //right
boo.c = 1; //right
return 0;
}
三、构造函数/析构函数/复制构造函数
构造函数:
构造函数的作用:在对象被创建时使用特定的值构造对象,将对象初始化为一个特定的初始状态。
class Complex{
public:
Complex(double r, double i = 0);
};
Complex c1; //错误,缺乏不带参数的构造函数
//若Complex(double r = 0, double i = 0);则可以执行,即缺省函数
Complex(2,1); //right
可以有多个构造函数(参数类型/个数不同),但只能有一个析构函数(可把delete语句放在析构函数中,先被构造的对象最后被析构掉)。
Test *pArray[3] = {new Test(4), new Test(1,2)};
//new Test()返回 Test* 类型,即用地址初始化指针数组;
//只生成两个对象,调用两个构造函数
//若无new,则不会调用相应的构造函数,指针不会引发对象生成
🚩 注 : 构造函数 不能被派生类继承
析构函数:
析构函数和构造函数的调用顺序
遵循原则:先被构造的函数后被析构掉
class Demo
{
int id;
public:
Demo(int i)
{
id = i;
cout << "id=" << id << " Constructor" << endl;
}
~Demo()
{
cout << "id=" << id << " Destructor" << endl;
}
};
Demo d1(1); //率先创建
void Func()
{
static Demo d2(2);
Demo d3(3);
cout << "Func" << endl;
}
int main()
{
Demo d4(4);
d4 = 6; //6被自动转换成一个Demo的*临时对象*,同时调用构造函数和析构函数
cout << "main" << endl;
{
Demo d5(5);
} //作用域
Func();
cout << "main ends" << endl;
return 0;
}
运行结果:
id=1 Constructor
id=4 Constructor
id=6 Constructor
id=6 Destructor //d4 = 6临时对象的消亡
main
id=5 Constructor
id=5 Destructor
id=2 Constructor
id=3 Constructor
Func
id=3 Destructor
main ends
id=6 Destructor //Demo d4对象的消亡
id=2 Destructor
id=1 Destructor
复制构造函数:
复制构造函数是一种特殊的构造函数,其形参为本类的对象引用。作用是用一个已存在的对象去初始化同类型的新对象。
复制构造函数被调用的三种情况:
用类的一个对象取初始化另一个对象时;
函数的返回值是类的对象,函数执行完成返回调用者时;
Point g(){
Point a(1,2);
return a;
}
int main(){
Point b;
b = g();
return 0;
}
a是g( )的局部对象,离开g( )之后就消亡了,不可能再返回主函数后继续生存。
所以这种情况下系统会创建一个临时无名对象,该临时对象的生存期只存在于函数调用所处的表达式中,即 b = g( )中。
执行语句 return a
,实际上是调用复制构造函数将a的值复制到临时对象中,函数g( )运行结束时对象a消亡,但临时对象会存在于表达式 b = g( ) 中,计算完这个表达式,临时对象也就自动消亡了。
函数的形参是类的对象,调用函数进行形参和实参结合时;
举例如下:
class Point
{ //Point 类的定义
public:
Point(int xx = 0, int yy = 0) //构造函数,内联
{
x = xx;
y = yy;
}
Point(const Point &p); //复制构造函数
void setX(int xx) { x = xx; }
void setY(int yy) { y = yy; }
int getX() const { return x; } //常函数(第5章)
int getY() const { return y; } //常函数(第5章)
private:
int x, y; //私有数据
};
//复制构造函数的实现
Point::Point(const Point &p)
{
x = p.x;
y = p.y;
cout << "Calling the copy constructor " << endl;
}
//形参为Point类对象
void fun1(Point p)
{
cout << p.getX() << endl;
}
//返回值为Point类对象
Point fun2()
{
Point a(1, 2);
return a;
}
int main()
{
Point a(4, 5);
Point b(a); //用a初始化b。
cout << b.getX() << endl;
fun1(b); //对象b作为fun1的实参
b = fun2(); //函数的返回值是类对象
cout << b.getX() << endl;
return 0;
}
拷贝构造函数和赋值运算符(=)有啥不同?
赋值运算符作用于一个已存在的对象;
拷贝构造函数会创建一个新对象。
四、类的组合
注意以下代码的构造函数和复制构造函数的调用顺序(原则:内嵌类先构造)
class Point
{ //Point类定义
public:
Point(int xx = 0, int yy = 0)
{
x = xx;
y = yy;
cout<<"constructor of Point!"<<endl;
}
Point(Point &p);
int getX() { return x; } //用于让其他类获得私有成员的值
int getY() { return y; }
private:
int x, y;
};
//复制构造函数的实现
Point::Point(Point &p)
{
x = p.x;
y = p.y;
cout << "Calling the copy constructor of Point" << endl;
}
//类的组合
class Line{ //Line类的定义
public:
//外部接口
Line(Point xp1, Point xp2);
Line(Line &l);
double getLen() { return len; }
private: //私有数据成员
Point p1, p2; //按照此顺序调用构造函数
double len;
};
//组合类的构造函数
Line::Line(Point xp1, Point xp2) : p2(xp2), p1(xp1) //仍然按照p1,p2的顺序调用构造函数
{
cout << "Calling constructor of Line" << endl;
double x = static_cast<double>(p1.getX() - p2.getX());
double y = static_cast<double>(p1.getY() - p2.getY());
len = sqrt(x * x + y * y);
}
//组合类的复制构造函数
Line::Line(Line &l) : p1(l.p1), p2(l.p2)
{
cout << "Calling the copy constructor of Line" << endl;
len = l.len;
}
//主函数
int main()
{
Point myp1(1, 1), myp2(4, 5);
//建立Point类的对象
Line line(myp1, myp2); //建立Line类的对象
Line line2(line); //利用复制构造函数建立一个新对象
cout << "The length of the line is: ";
cout << line.getLen() << endl;
cout << "The length of the line2 is: ";
cout << line2.getLen() << endl;
return 0;
}
五、结构体和联合体
struct
union
例如:使用联合体保存成绩信息,并且输出。
#include <string>
#include <iostream>
using namespace std;
class ExamInfo
{
private:
string name; //课程名称
enum
{
GRADE,
PASS,
PERCENTAGE
} mode; //计分方式
union {
char grade; //等级制的成绩
bool pass; //只记是否通过课程的成绩
int percent; //百分制的成绩
};
public: //三种构造函数,分别用等级、是否通过和百分初始化
ExamInfo(string name, char grade) : name(name), mode(GRADE), grade(grade) {}
ExamInfo(string name, bool pass) : name(name), mode(PASS), pass(pass) {}
ExamInfo(string name, int percent) : name(name), mode(PERCENTAGE), percent(percent) {}
void show();
};
void ExamInfo::show()
{
cout << name << ": ";
switch (mode)
{
case GRADE:
cout << grade;
break;
case PASS:
cout << (pass ? "PASS" : "FAIL");
break;
case PERCENTAGE:
cout << percent;
break;
}
cout << endl;
}
int main()
{
ExamInfo course1("English", 'B');
ExamInfo course2("Calculus", true);
ExamInfo course3("C++ Programming", 85);
course1.show();
course2.show();
course3.show();
return 0;
}
六、C++中的 . 操作符与 -> 操作符
struct Person
{
String name;
String born;
double money;
};
Person A;
Person *B = new Person;
A.name = "Dr.nothing";
B->name = "Dr.something"; //B->name = (*B).name
A.money = 300.0;
(*B).money = 30;
若是使用到
->
操作符则左边的变量必须是指针变量;若是使用到
.
操作符那么左边的变量不能为指针,指针变量需要使用*
操作符访问到该地址的内容