c++ 类和对象总结

话不多说,我们直接进入主题:
对象:客观世界里的一切事物都可以看作是一个对象,每一个对象应当具有属性(静态特征,比如一个班级,一个专业,一个教室)和行为(动态特征,例如:学习,开会,体育比赛等)两个要素。 对象是由一组属性和一组行为构成的。
类(class):就是对象的类型,代表了某一批对象的共同特性和特征。类是对象的抽象,而对象是类的具体实例。

2.1 类的引入

在C语言中我们定义一个结构体是这样定义的:

struct Student
{
  int _age;
  char* _Gender;
  char* _Name;
};
int main()
{
  struct S;
  return 0;
}

我们都知道,在C中,“数据”和“处理数据的操作(函数)”是分开的,语言本身并没有支持“数据和函数”之间的关联性。那么,如果我们要在某种特定情况下让数据和函数有一定的关联,这个时候我们应该怎么处理呢?
先看一个例子:

很明显,编译器报错了,还很多。也就是说在C语言当中是不允许在结构体中定义函数的,那么在C++中是不是也是这样呢?

通过对比,我们明显的发现C++是可以做到我们想要将数据和函数产生一定关系的操作的。
为了区别C语言中结构体的定义struct,在C++中我们常用class来代替struct。

2.2 类的定义

#include <iostream>
using namespace std;
class Student
{
public:
  char* _name;
private:
  char* _Gender;
  int _age;
};
int main()
{
  class S;
  return 0;
}

class是C++中定义类的关键字,Student为类的名字,{}中为类的主体,和结构体类似,在{}后面跟的是;。类中的元素称为类的成员,类中的数据称为类的属性或者类的成员变量,类中的函数称为类的成员函数。

类的定义通常有两种方式:

1、将类的声明和定义都放在类体中za
2、将类的声明放在.h头文件中,定义放在.cpp文件中

在代码中我们看到了private 和 public两个没有见过的东西,接下来我们讲一讲C++的三大特性:继承 封装 多态
封装:隐藏对象的属性和现实细节,仅对外公开接口和对象进行交互,将数据和操作数据的方法有机结合。

这里的public 和 private是C++中的访问限定符,访问限定符有三个:public (公有) protected(保护) private(私有)。在下面的博文中我们会用到这些限定符,具体情况后续文章再作介绍,这里读者只需了解就可。

这里做一些说明:

1、public成员在类外可以直接访问
2、protected和private成员在类外不能够直接访问,在这里我们简单的把他们看成一样的。(二者区别就是基类private成员在派生类中是不能被访问的,如果基类成员不想再类外被访问,但需要在派生类中能访问,就定义为protected,后面博文更到派生类时我们会再来把这两个东西拿出来再讲一讲)
3、他们的作用域从该访问限定符出现的位置开始直到下一个访问限定符出现截止
4、class的默认访问权限是private,而struct默认访问权限是public(因为struct要兼容C的特点)

那么我们如何在类外访问一个类中的私有成员变量呢?(面试题)

方法一:在类中添加一个共有的方法

我们可以看到在public中定义的公有函数可以在类外访问私有成员变量,这是访问的一种方法。

类的作用域

在C语言阶段我们知道变量的作用域只有局部域和全局域两种,而在C++作用域则分为了局部域、全局域、命名空间域和类域四种,前面几种域相信我们都已将熟悉过,这里我讲一下类域。

类定义了一个新的作用域,类的所有成员都必须处在类的作用域中。形参表和函数体处于类的作用域中。在类体外定义成员,需要用 :: 作用域解析符指明成员属于哪一个类域。在类的作用域外,只能通过对象(或指针)借助成员访问操作符 . 和->来访问类成员,跟在访问操作符后面的名字必须在相关联的类的作用域中。

下面我们看看在代码中如何实现上述的意思:

#define _CRT_SECURE_NO_WARNINGS 1

#include <iostream>
using namespace std;

namespace N1  //命名空间域
{
  int a = 10;
}

int a = 20;   //全局域

void FunTest()
{
  cout << "FunTest()" << endl;
}
class Test
{
public:
  void SetA(int a)
  {
    a = a;      //存在歧义,是变量给变量赋值呢还是形参给变量赋值,或者变量给形参赋值呢?同学们不要这样写
    //实际证明,这里的赋值是形参给形参赋值,结果并没有改变变量的值,结果出了函数作用域自然是一个随机值 正确写法: **_a = a;**
  }
  void PrintA()
  {
    cout << a << endl;  //cout << _a <<endl;
  }
private:
  int a;         //类域  正确写法:int _a;
};
int main()
{
  int a = 40;       //局部域
  Test t;
  t.SetA(30);
  cout << N1::a << endl;   //打印命名空间域的值
  cout << ::a << endl;    //打印全局域的值
  cout << a << endl;     //打印局部域的值
  t.PrintA();         //打印类域的值
  return 0;
}

看完这串代码不知道各位有没有什么疑惑呢?
这里附上这段代码的结果:

我们本应该想让编译器给我们打印出10 20 30 40这几个值,结果最后却给了我们一个乱码,这是为什么呢?
细心的同学应该发现了,在这里我们定义的所有的变量都是用的同一个名称a,这样的编码习惯是极不好的,容易引起误会,上面就给了一个反例。

在使用一个变量时,我们应当注意必须要先声明后使用

2.2 类的对象的模型

类对象模型:类中各成员在内存中的布局形式。
下面我们以代码形式举例说明一下:

class Student
{
public:
  void SetStudentInfo(char* name, char* gender, int age)
  {
    strcpy(_name, name);
    strcpy(_gender, gender);
    _age = age;
  }
  void PrintInfo()
  {
    cout << _name << " " << _gender << " " << _age << endl;
  }
private:
  char _name[20];
  char _gender[3];
  int _age;
};
int main()
{
  Student s1, s2;
  cout << sizeof(s1) << endl;
  s1.SetStudentInfo("鸣人", "男", 14);
  s2.SetStudentInfo("佐助", "男", 14);
  return 0;
}

既然一个类有那么多成员和不同的对象,那么它到底是怎么来存储的呢?

下面给出三种假设:

假设一

假设二:

那就剩最后一种假设了:

显然。这种假设才是成立的。

提一个问题:C++是怎么计算一个类的大小的?

我们在程序中验证一下:

class A1
{
public:
  void f1()
  {}
  void f2()
  {}
}; 

class A2
{
public:
  void f1()
  {}
private:
  int a = 10;
};
class A3
{};

int main()
{
  cout << sizeof(A1) << endl;  //1
  cout << sizeof(A2) << endl;  //4
  cout << sizeof(A3) << endl;  //1
  return 0;
}

可以看到在有成员变量的时候得到的值是4,而一个空类和只有成员函数的时候它的值是1,难道是成员函数的大小?
显然是不对的,前面我们说过,成员函数是不占大小的,因此我们可以得出结论:一个类的大小,实际上就是该类中非静态成员变量之和,当然也要注意内存对齐,空类大小值为一(在Linux和VS下面是 1)
为什么是一呢?
就是为了区分不同的对象,设计 1 是为了 节省空间

(0)

相关推荐

  • C++类和对象实例解析(二)

    C++既是面向对象也是面向过程的语言,在这里就有一个重要的概念--类.         何谓类?类是对对象的一种抽象,举例来讲:每一个实实在在存在的人就是一个对象,人有很多共同的特征(一个头,两条腿,能走,能跑),这具有共同特征的人就成为一个类.类是一个抽象的名词,每一个人(即对象)是这个类的实例.         对象间具有的共同特征是对象的属性和行为.录像机是一个对象,它的属性是生产厂家.牌子.重量.颜色等等,它的行为就是它的功能,如录像.放像.快进.倒退等操作. C++程序中,需要先定义一

  • C++11/14 线程调用类对象和线程传参的方法

    线程调用类对象 在前面的示例中,我们为线程任务使用了通常的函数.实际上,我们可以使用任何可调用对象或者lambda函数,如下调用类对象的例子: #include <iostream> #include <thread> class MyFunctor { public: void operator()() { std::cout << "functor\n"; } }; int main() { MyFunctor fnctor; std::thre

  • C++之类和对象课后习题简单实例

    建立一个对象数组,内放5个学生的(学号,成绩),设立一个函数max,用指向对象的指针作函数参数,在max函数中找出5个学生的最高成绩者,并输出其学号. #include<iostream> using namespace std; class Student {public: Student(int=10,int=0); int number; int score; void display(); }; Student::Student(int num,int sco):number(num)

  • 详解C++编程中类的声明和对象成员的引用

    C++类的声明和对象的创建 类是创建对象的模板,一个类可以创建多个对象,每个对象都是类类型的一个变量:创建对象的过程也叫类的实例化.每个对象都是类的一个具体实例(Instance),拥有类的成员变量和成员函数. 与结构体一样,类只是一种复杂数据类型的声明,不占用内存空间.而对象是类这种数据类型的一个变量,占用内存空间. 类的声明 类是用户自定义的类型,如果程序中要用到类,必须先进行声明,或者使用已存在的类(别人写好的类.标准库中的类等),C++语法本身并不提供现成的类的名称.结构和内容. 一个简

  • c++ 面向对象的类设计

    类的设计在于用恰到好处的信息来完整表达一个职责清晰的概念,恰到好处的意思是不多也不少,少了,就概念就不完整:多了,就显得冗余,累赘,当然特例下,允许少许的重复,但是,这里必须要有很好的理由.冗余往往就意味着包含了过多的信息,概念的表达不够精准,好比goto,指针,多继承这些货色,就是因为其过多的内涵,才要严格限制其使用.好像,more effective c++上说的,class的成员函数,应该是在完整的情况下保持最小化.但是,这里我们的出发点,是成员数据的完整最小化. 最小化的好处是可以保持概

  • C++ 中类对象类型的转化的实例详解

    C++ 中类对象类型的转化的实例详解 前言: 存在继承关系的类的对象之间可以进行转化: 子类对象类型可以转化为父类类型, 例如,一个函数的参数是父类对象,而传递进来的参数是子类对象,那么子类对象类型自动转化父类对象: 但是父类对象不能转为子类对象. 代码: # include <iostream> using namespace std; class A { public: void printm() { cout<<"A::print()"<<en

  • 浅谈C++中派生类对象的内存布局

    主要从三个方面来讲: 1 单一继承 2 多重继承 3 虚拟继承 1 单一继承 (1)派生类完全拥有基类的内存布局,并保证其完整性. 派生类可以看作是完整的基类的Object再加上派生类自己的Object.如果基类中没有虚成员函数,那么派生类与具有相同功能的非派生类将不带来任何性能上的差异.另外,一定要保证基类的完整性.实际内存布局由编译器自己决定,VS里,把虚指针放在最前边,接着是基类的Object,最后是派生类自己的object.举个栗子: class A { int b; char c; }

  • C++内核对象封装单实例启动程序的类

    复制代码 代码如下: //File Name: Singleton.h#pragma once class Singleton{private:    CString strGUID;    CString strMapFileGUID; HANDLE m_hSingleton; public:    Singleton();    ~Singleton();public:    void AppStart (const HWND & hWnd) const;}; 复制代码 代码如下: //Fi

  • 详解C++编程中的输入输相关的类和对象

    C++输入和输出的概念 我们经常用到的输入和输出,都是以终端为对象的,即从键盘输入数据,运行结果输出到显示器屏幕上.从操作系统的角度看,每一个与主机相连的输入输出设备都被看作一个文件.除了以终端为对象进行输入和输出外,还经常用磁盘(光盘)作为输入输出对象,磁盘文件既可以作为输入文件,也可以作为输出文件. 程序的输入指的是从输入文件将数据传送给程序,程序的输出指的是从程序将数据传送给输出文件. C++输入输出包含以下三个方面的内容: 对系统指定的标准设备的输入和输出.即从键盘输入数据,输出到显示器

  • Python面向对象编程中的类和对象学习教程

    Python中一切都是对象.类提供了创建新类型对象的机制.这篇教程中,我们不谈类和面向对象的基本知识,而专注在更好地理解Python面向对象编程上.假设我们使用新风格的python类,它们继承自object父类. 定义类 class 语句可以定义一系列的属性.变量.方法,他们被该类的实例对象所共享.下面给出一个简单类定义: class Account(object): num_accounts = 0 def __init__(self, name, balance): self.name =

  • 关于JavaScript定义类和对象的几种方式

    可以看看这个例子: 复制代码 代码如下: var a = 'global'; (function () { alert(a); var a = 'local'; })(); 大家第一眼看到这个例子觉得输出结果是什么?'global'?还是'local'?其实都不是,输出的是undefined,不用迷惑,我的题外话就是为了讲这个东西的. 其实很简单,看一看JavaScript运行机制就会明白.我们可以把这种现象看做"预声明".但是如果稍微深究一下,会明白得更透彻. 这里其实涉及到对象属性

  • JavaScript定义类和对象的方法

    本文实例讲述了JavaScript定义类和对象的方法.分享给大家供大家参考.具体方法如下: 在JS中,类和对象有多种不同的写法,因为本人对JS也不怎么熟,所以就本人的理解来写,如果哪位朋友发现有不对,请告之,共同学习. JS定义一个类有两种定法(我只知道这两种): 1. 定义函数的方式: 定义: 复制代码 代码如下: function classA(a) {      this.aaa=a;  //添加一个属性      this.methodA=function(ppp)  //添加一个方法

  • javaScript中定义类或对象的五种方式总结

    第一种方式: 工厂方法 能创建并返回特定类型的对象的工厂函数(factory function). function createCar(sColor){ var oTempCar = new Object; oTempCar.color = sColor; oTempCar.showColor = function (){ alert(this.color); }; return oTempCar; } var oCar1 = createCar(); var oCar2 = createCa

  • Javascript学习笔记5 类和对象

    面向对象语言三大特点:继承,多态,封装,这三点虽然Javascript没有提供天然的语法实现,但是我们都可以通过prototype等技巧来实现,因此这种说法似乎不过分. 在Javascript中,构造对象有三种方式: 1. 首先,我们要明确一个概念,Javascript是一种弱类型的语言,一方面体现在Javascript的变量,返回类型都是没有强类型约束的,另一方面,Javascript可以为对象任意添加属性和方法.根据这个,我们可以写出这样的代码: 复制代码 代码如下: <script typ

  • Javascript创建类和对象详解

    现总结一下Javascript创建类和对象的几种方法: 1.原始的创建方法: <script type="text/javascript"> var person = new Object(); person.name="Amy"; person.sex="Woman"; person.show=function(){ document.write("name is: "+this.name+" ; se

  • js 用于检测类数组对象的函数方法

    如下所示: //判定o是否是一个类数组对象 //字符串和函数有length属性,但是它们 //可以用typeof检测将其排除.在客户端JavaScript中,DOM文本节点 //也有length属性,需要用额外判断o.nodeType!=3将其排除 function isArrayLike(o){ if(o&&//o非null/undefined等 typeof o==="object"&&//o是对象 isFinite(o.length)&&a

  • php基础知识:类与对象(5) static

    Declaring class members or methods as static makes them accessible without needing an instantiation of the class. A member declared as static can not be accessed with an instantiated class object (though a static method can).  声明静态的类变量和方法可以不需要实例化类对象的

  • php使用变量动态创建类的对象用法示例

    本文实例讲述了php使用变量动态创建类的对象.分享给大家供大家参考,具体如下: 这是一个能用变量动态创建类的对象的用法,就是根据$pay_code变量值来创建对象. 例如下例就是创建类T的一个对象$payment.然后就可以使用了.咋一看像是个新的知识点,其实不然,只不过是编程中的一个技巧而已. $pay_code='T'; $payment = new $pay_code(); echo $payment; echo $payment->ep(); class T{ function ep()

  • PHP类和对象相关系统函数与运算符小结

    本文总结了PHP类和对象相关系统函数与运算符.分享给大家供大家参考,具体如下: 系统函数 class_exists() 判断某个类是否存在 interface_exists() 判断接口是否存在 get_class() / __CLASS__ 获取某个对象所处的类名 get_parent_class() 获取某个对象所属父类的类名 get_class_methods() 获取一个类所有方法,返回索引数组 get_class_vars() 获取一个类所有属性,下标为属性名 get_declared

随机推荐