1、C++ 类 & 对象
C++ 在 C 语言的基础上增加了面向对象编程,C++ 支持面向对象程序设计。类是 C++ 的核心特性,通常被称为用户定义的类型。
类用于指定对象的形式,是一种用户自定义的数据类型,它是一种封装了数据和函数的组合。类中的数据称为成员变量,函数称为成员函数。类可以被看作是一种模板,可以用来创建具有相同属性和行为的多个对象。
1、1类的定义
定义一个类需要使用关键字 class,然后指定类的名称,并类的主体是包含在一对花括号中,主体包含类的成员变量和成员函数。
定义一个类,本质上是定义一个数据类型的蓝图,它定义了类的对象包括了什么,以及可以在这个对象上执行哪些操作。
类的访问,使用.,类的定义,
#define _CRT_SECURE_NO_WARNINGS
#include <iostream>
using namespace std;
class Box {
public:
double lenth;
double breadth;
double height;
double get(void) {
return lenth * breadth * height;
}
void set(double _lenth, double _breadth, double _height)
{
this->lenth = _lenth;
this->breadth = _breadth;
this->height = _height;
}
};
int main()
{
Box box1;//Box类就像一种数据类型,box1是他定义的变量
Box box2;//使用函数定义
//如何访问数据成员,使用.
box1.height = 5;
box1.lenth = 6;
box1.breadth = 7;
cout << "box1的体积:" << box1.get() << endl;
box2.set(10, 20, 30);
cout << "box1的体积:" << box2.get() << endl;
return 0;
}
1、2类的成员函数
类的成员函数是指那些把定义和原型写在类定义内部的函数,就像类定义中的其他变量一样。类成员函数是类的一个成员,它可以操作类的任意对象,可以访问对象中的所有成员。
在类定义中定义的成员函数把函数声明为内联的
class Box {
public:
double lenth;
double breadth;
double height;
double get(void) {
return lenth * breadth * height;
}
您也可以在类的外部使用范围解析运算符 :: 定义该函数
class Box {
public:
double lenth;
double breadth;
double height;
double get(void);
};
double Box::get(void) {
return lenth * breadth * height;
}
1、3类访问修饰符
数据封装是面向对象编程的一个重要特点,它防止函数直接访问类类型的内部成员。类成员的访问限制是通过在类主体内部对各个区域标记 public、private、protected 来指定的。关键字 public、private、protected 称为访问修饰符。
一个类可以有多个 public、protected 或 private 标记区域。每个标记区域在下一个标记区域开始之前或者在遇到类主体结束右括号之前都是有效的。成员和类的默认访问修饰符是 private。
1、公有成员public
公有成员在程序中类的外部是可访问的。您可以不使用任何成员函数来设置和获取公有变量的值,如下所示:
#define _CRT_SECURE_NO_WARNINGS
#include <iostream>
using namespace std;
class Line {
public:
double lenth;
void setlenth(double len);
double getlenth();
};
void Line::setlenth(double len) {
lenth = len;
}
double Line::getlenth() {
return lenth;
}
int main()
{
Line object;
object.setlenth(10);
cout << "lenth:" << object.getlenth() << endl;
//直接调用共有类的变量,给其赋值
object.lenth = 20;
cout << "lenth:" << object.getlenth() << endl;//运行ok
return 0;
}
lenth:10
lenth:20
2、私有成员private
私有成员变量或函数在类的外部是不可访问的,甚至是不可查看的。只有类和友元函数可以访问私有成员。
默认情况下,类的所有成员都是私有的。
这意味着,如果您没有使用任何访问修饰符,类的成员将被假定为私有成员。
定义一个私有的宽度变量
using namespace std;
class Line {
public:
double lenth;
void setlenth(double len);
double getlenth();
void setwidth(double _width);
double getwidth();
private:
double width;
};
//void Line::setlenth(double len) {
// lenth = len;
//}
//double Line::getlenth() {
// return lenth;
//}
void Line::setwidth(double _width) {
this->width = _width;
}
double Line::getwidth() {
return width;
}
int main()
{
Line object;
//object.setlenth(10);
//cout << "lenth:" << object.getlenth() << endl;
直接调用共有类的变量,给其赋值
//object.lenth = 20;
//cout << "lenth:" << object.getlenth() << endl;//运行ok
object.setwidth(10);
cout << "width:" << object.getwidth() << endl;
使用成员函数可以获取width
但是直接调用类内的变量去赋值的话,会报错
3、protected(受保护)成员
protected(受保护)成员变量或函数与私有成员十分相似,但有一点不同,protected(受保护)成员在派生类(即子类)中是可访问的。
#define _CRT_SECURE_NO_WARNINGS
#include <iostream>
using namespace std;
//基类
class Line {
protected:
double height;
};
//box是派生类
class box :Line{
public:
void setLineHeight(double _height);
double getLineHeight();
};
void box::setLineHeight(double _height) {
this->height = _height;
}
double box::getLineHeight() {
return this->height;
}
int main()
{
box object;
//使用成员函数设置
object.setLineHeight(10);
cout << "lenth:" << object.getLineHeight() << endl;
//直接调用共有类的变量,给其赋值
//object.height = 20;
//cout << "lenth:" << object.getLineHeight() << endl;//运行ok
return 0;
}
4、继承的特点
有public, protected, private三种继承方式,它们相应地改变了基类成员的访问属性。
-
1.public 继承:基类 public 成员,protected 成员,private 成员的访问属性在派生类中分别变成:public, protected, private
-
2.protected 继承:基类 public 成员,protected 成员,private 成员的访问属性在派生类中分别变成:protected, protected, private
-
3.private 继承:基类 public 成员,protected 成员,private 成员的访问属性在派生类中分别变成:private, private, private
但无论哪种继承方式,下面两点都没有改变:
-
1.private 成员只能被本类成员(类内)和友元访问,不能被派生类访问;
-
2.protected 成员可以被派生类访问。
1、public的继承
public继承,public还是public,protected还是protectde,private还是private
使用成员函数可以访问public和protected
类外不能访问protected和private
#define _CRT_SECURE_NO_WARNINGS
#include <iostream>
using namespace std;
//基类
class Base {
public:
int num;
Base() {
num = 10;
num1 = 20;
num2 = 30;
num3 = 40;
}
void fun() {
cout << num << endl;
cout << num1 << endl;
cout << num2 << endl;
cout << num3 << endl;
}
public:
int num1;
protected:
int num2;
private:
int num3;
};
class son :public Base {
public:
int num;
son(int _num) {
Base();
num = _num;
}
void func() {
cout << num << endl;
cout << num1 << endl;//基类public,子类也是
cout << num2 << endl;//基类protected,子类也是
//cout << num3 << endl;//基类private,子类不可访问
}
};
int main()
{
son jack(10);
jack.func();//可以用成员函数访问public,protected
cout << jack.num << endl;
cout << jack.num1 << endl;
//cout << jack.num2 << endl;
//cout << jack.num3 << endl;
//类外不能访问protected和private成员
return 0;
}
2、protected继承
protected继承,public变成 protected,protected还是protectde,private还是private
使用成员函数可以访问public和protected
类外不能访问protected和private
class son :protected Base {
public:
int num;
son(int _num) {
Base();
num = _num;
}
void func() {
cout << num << endl;//protected继承
cout << num1 << endl;//基类public,子类是protected
cout << num2 << endl;//基类protected,子类是protected
//cout << num3 << endl;//基类private,子类不可访问
}
};
int main()
{
son jack(10);
jack.func();//可以用成员函数访问protected
cout << jack.num << endl;
//cout << jack.num1 << endl;
//cout << jack.num2 << endl;
//cout << jack.num3 << endl;
//类外不能访问protected和private成员
return 0;
}
3、private继承
private继承,public变成 private,protected变成private,private还是private
使用成员函数可以访问自身的private,但是不能访问父类的
类外不能访问protected和private
class son :private Base {
public:
int num;
son(int _num) {
Base();
num = _num;
}
void func() {
cout << num << endl;//private继承
cout << num1 << endl;//基类public,子类是private
cout << num2 << endl;//基类protected,子类是private
//cout << num3 << endl;//基类private,子类不可访问
}
};
int main()
{
son jack(10);
jack.func();//可以用成员函数访问protected
cout << jack.num << endl;//num是子类公有变量
//cout << jack.num1 << endl;
//cout << jack.num2 << endl;
//cout << jack.num3 << endl;
//类外不能访问protected和private成员
return 0;
}
1、4、构造函数和析构函数
类的构造函数是类的一种特殊的成员函数,它会在每次创建类的新对象时执行。
构造函数的名称与类的名称是完全相同的,并且不会返回任何类型,也不会返回 void。构造函数可用于为某些成员变量设置初始值。
1、默认的构造函数没有任何参数,
但如果需要,构造函数也可以带有参数
class Base{
public:
Base(){
cout << "this is Base_function " << endl;
}
};
2、带参数的构造函数
作用:这样在创建对象时就会给对象赋初始值。
其实就是初始化的意思。
class Base{
public:
Base(int _num){
cout << "this is Base_function " << endl;
this->num = _num;
}
private:
int num;
};
***** 使用初始化列表来初始化字段:
Base::Base(int _num):num(_num){
cout << "this is Base_function " << endl;
}
等用于
class Base{
public:
Base(int _num);
private:
int num;
};
Base::Base(int _num){
cout << "this is Base_function " << endl;
this->num = _num;
}
3、类的析构函数
类的析构函数是类的一种特殊的成员函数,它会在每次删除所创建的对象时执行。
析构函数的名称与类的名称是完全相同的,只是在前面加了个波浪号(~)作为前缀,它不会返回任何值,也不能带有任何参数。析构函数有助于在跳出程序(比如关闭文件、释放内存等)前释放资源。
1、5拷贝构造函数
拷贝构造函数是一种特殊的构造函数,它在创建对象时,是使用同一类中之前创建的对象来初始化新创建的对象。拷贝构造函数通常用于:
-
通过使用另一个同类型的对象来初始化新创建的对象。
-
复制对象把它作为参数传递给函数。
-
复制对象,并从函数返回这个对象。
如果在类中没有定义拷贝构造函数,编译器会自行定义一个。如果类带有指针变量,并有动态内存分配,则它必须有一个拷贝构造函数。
#define _CRT_SECURE_NO_WARNINGS
#include <iostream>
using namespace std;
class Base {
public:
int get();
Base(int len);
Base(const Base& obj);
~Base();
private:
int* ptr;
};
Base::Base(int len) {
cout << "构造 " << endl;
ptr = new int;
*ptr = len;
}
Base::Base(const Base &obj) {
cout << "调用拷贝构造为指针ptr分配内存 " << endl;
ptr = new int;
*ptr = *obj.ptr;
}
Base::~Base() {
cout << "释放内存 " << endl;
delete ptr;
}
int Base::get() {
return *ptr;
}
void display(Base obj) {
cout << "size Base :" << obj.get() << endl;
}
int main()
{
Base line(10);
display(line);
return 0;
}
1、6友元函数
类的友元函数是定义在类外部,但有权访问类的所有私有(private)成员和保护(protected)成员。尽管友元函数的原型有在类的定义中出现过,但是友元函数并不是成员函数。
友元可以是一个函数,该函数被称为友元函数;友元也可以是一个类,该类被称为友元类,在这种情况下,整个类及其所有成员都是友元。
如果要声明函数为一个类的友元,需要在类定义中该函数原型前使用关键字 friend,如下所示:
class Box { double width; public: double length; friend void printWidth( Box box ); void setWidth( double wid ); };
声明类 ClassTwo 的所有成员函数作为类 ClassOne 的友元,需要在类 ClassOne 的定义中放置如下声明:
friend class ClassTwo;
请注意:printWidth() 不是任何类的成员函数
/* 因为 printWidth() 是 Box 的友元,它可以直接访问该类的任何成员 */
#define _CRT_SECURE_NO_WARNINGS
#include <iostream>
using namespace std;
class Base {
public:
void setWidth(double _width);
friend void printWidth(Base obj);
private:
double width;
};
void Base::setWidth(double _width)
{
this->width = _width;
}
void printWidth(Base obj) {
cout << "width of Base:" << obj.width << endl;
}
int main()
{
Base obj;
obj.setWidth(10);
printWidth(obj);
}
1、7内联·函数·
C++ 内联函数是通常与类一起使用。如果一个函数是内联的,那么在编译时,编译器会把该函数的代码副本放置在每个调用该函数的地方。
对内联函数进行任何修改,都需要重新编译函数的所有客户端,因为编译器需要重新更换一次所有的代码,否则将会继续使用旧的函数。
如果想把一个函数定义为内联函数,则需要在函数名前面放置关键字 inline,在调用函数之前需要对函数进行定义。如果已定义的函数多于一行,编译器会忽略 inline 限定符。
1、8C++中的this指针
在 C++ 中,this 指针是一个特殊的指针,它指向当前对象的实例。
在 C++ 中,每一个对象都能通过 this 指针来访问自己的地址。
this是一个隐藏的指针,可以在类的成员函数中使用,它可以用来指向调用对象。
当一个对象的成员函数被调用时,编译器会隐式地传递该对象的地址作为 this 指针。
友元函数没有 this 指针,因为友元不是类的成员,只有成员函数才有 this 指针。
class MyClass {
private:
int value;
public:
void setValue(int value) {
this->value = value;
}
以上实例中,我们定义了一个名为 MyClass 的类,它有一个私有成员变量 value。
类中的 setValue() 函数用于设置 value的 值,
在 setValue() 函数中,我们使用 this 指针来引用当前对象的成员变量 value,并将传入的值赋给它,这样可以明确地告诉编译器我们想要访问当前对象的成员变量,而不是函数参数或局部变量。
1、9C++中指向类的指针
一个指向 C++ 类的指针与指向结构的指针类似,访问指向类的指针的成员,需要使用成员访问运算符 ->,就像访问指向结构的指针一样。与所有的指针一样,您必须在使用指针之前,对指针进行初始化。
#define _CRT_SECURE_NO_WARNINGS
#include <iostream>
using namespace std;
class Base {
public:
Base(double _len=2, double _bread=4, double _height=6)
{
this->breadth = _bread;
this->height = _height;
this->length = _len;
}
double Volume() {
return length * breadth * height;
}
private:
double length;
double breadth;
double height;
};
int main()
{
Base base1(1,2,3);
Base base2(4,5,6);
Base* ptr;
ptr = &base1;//指向第一个变量的地址
cout << ptr->Volume() << endl;
ptr = &base2;
cout << ptr->Volume() << endl;
}
1、10C++类的静态成员
我们可以使用 static 关键字来把类成员定义为静态的。当我们声明类的成员为静态时,这意味着无论创建多少个类的对象,静态成员都只有一个副本。
#define _CRT_SECURE_NO_WARNINGS
#include <iostream>
using namespace std;
class Box {
public:
static int objectCount;
Box(double l = 2, double b = 2, double h = 2)
{
length = l;
breadth = b;
height = h;
objectCount++;
}
private:
double length;
double breadth;
double height;
};
//初始化类Box静态成员
int Box::objectCount = 0;
int main()
{
Box box1(1, 2, 3);
Box box2(2, 3, 4);
Box obj[9];
cout << "num_obj :" << Box::objectCount << endl;
}
静态成员函数
如果把函数成员声明为静态的,就可以把函数与类的任何特定对象独立开来。静态成员函数即使在类对象不存在的情况下也能被调用,静态函数只要使用类名加范围解析运算符 :: 就可以访问。
静态成员函数只能访问静态成员数据、其他静态成员函数和类外部的其他函数。
静态成员函数有一个类范围,他们不能访问类的 this 指针。您可以使用静态成员函数来判断类的某些对象是否已被创建。
静态成员函数与普通成员函数的区别:
- 静态成员函数没有 this 指针,只能访问静态成员(包括静态成员变量和静态成员函数)。
- 普通成员函数有 this 指针,可以访问类中的任意成员;而静态成员函数没有 this 指针。