c++ 类

代码实例:

#include <iostream>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
using namespace std;
class Stack
{
public:
Stack(int size=1024);
~Stack();
void init();
bool isEmpty();
bool isFull();
void push(int data);
int pop();
private:
int* space;
int top;
};
Stack::Stack(int size)
{
space = new int[size];
top = 0;
}
Stack::~Stack()
{
delete []space;
}
//void Stack::init()
//{
// memset(space,0,sizeof(space));
// top = 0;
//}
bool Stack::isEmpty()
{
return top == 0;
}
bool Stack::isFull()
{
return top == 1024;
}
void Stack::push(int data)
{
space[top++] = data;
}
int Stack::pop()
{
return space[--top];
}
int main()
{
// Stack s;
Stack s(100);
// s.init();
if(!s.isFull())
s.push(10);
if(!s.isFull())
s.push(20);
if(!s.isFull())
s.push(30);
if(!s.isFull())
s.push(40);
if(!s.isFull())
s.push(50);
while(!s.isEmpty())
cout<<s.pop()<<endl;
return 0;
}

1、构造器(Constructor):

在类对象创建时,自动调用,完成类对象的初始化。尤其是动态堆内存的申请。
规则:
1 在对象创建时自动调用,完成初始化相关工作。
2 无返回值,与类名同,
3 可以重载,可默认参数。
4 默认无参空体,一经实现,默认不复存在。

class 类名
{
类名(形式参数)
构造体
}
class A
{
A(形参)
{}
}

比如:

Stack::Stack(int size)
{
space = new int[size];
top = 0;
}

private和public,类对象可以直接访问公有成员,但只有公有成员函数内部来访问对象的私有成员

析造器(Destructor):析构函数的作用,并不是删除对象,而在对象销毁前完成的一些清理工作。
对象销毁时期
1、栈对象离开其作用域。
2、堆对象被手动 delete.

定义:
class 类名
{
~类名()
析造体
}
class A
{
~A()
{}
}

在类对像销毁时,自动调用,完成对象的销毁。尤其是类中己申请的堆内存的释放.
规则:
1 对象销毁时,自动调用。完成销毁的善后工作。
2 无返值,与类名同,无参。不可以重载与默认参数。
3 系统提供默认空析构器,一经实现,不复存在。
Stack::~Stack()
{
delete []space;
}

this 指针

系统在创建对象时,默认生成的指向当前对象的指针。这样作的目的,就是为了带来方
便

1,避免构造器的入参与成员名相同。
2,基于 this 指针的自身引用还被广泛地应用于那些支持多重串联调用的函数中。
比如连续赋值

#include <iostream>
using namespace std;
class Stu
{
public:
Stu(string name, int age) // :name(name),age(age)
{
this->name = name;
this->age = age;
}
Stu & growUp()
{
this->age++;
return *this; // return this; ??
}
void display()
{
cout<<name<<" : "<<age<<endl;
}
private:
string name;
int age;
};
int main()
{
Stu s("wangguilin",30);
s.display();
s.growUp().growUp().growUp().growUp().growUp();
s.display();
return 0;
}

类继承

在 C++中可重用性(software reusability)是通过继承(inheritance)这一机制来实现的。如果没有掌握继承性,就没有掌握类与对象的精华

#include <iostream>
using namespace std;
class Person
{
public:
void eat(string food)
{
cout<<"i am eating "<<food<<endl;
}
};
class Student:public Person
{
public:
void study(string course)
{
cout<<"i am a student i study "<<course<<endl;
}
};
class Teacher:public Person
{
public:
void teach(string course)
{
cout<<"i am a teacher i teach "<<course<<endl;
}
};
int main()
{
Student s;
s.study("C++");
s.eat("黄焖鸡");
Teacher t;
t.teach("Java");
t.eat("驴肉火烧");
return 0;
}

类的继承,是新的类从已有类那里得到已有的特性。或从已有类产生新类的过程就是类的派生。原有的类称为基类或父类,产生的新类称为派生类或子类。派生与继承,是同一种意义两种称谓。

派生类的声明:
class 派生类名:[继承方式] 基类名
{
派生类成员声明;
};

一个派生类可以同时有多个基类,这种情况称为多重继承,派生类只有一个基类,称为单继承。下面从单继承讲起

继承方式规定了如何访问基类继承的成员。继承方式有 public, private, protected。继承方式不影响派生类的访问权限,影响了从基类继承来的成员的访问权限,包括派生类内的访问权限和派生类对象。
简单讲:
公有继承:基类的公有成员和保护成员在派生类中保持原有访问属性,其私有成员仍为基类的私有成员。
私有继承:基类的公有成员和保护成员在派生类中成了私有成员,其私有成员仍为基类的私有成员。
保护继承:基类的公有成员和保护成员在派生类中成了保护成员,其私有成员仍为基类的私有成员

pretected 对于外界访问属性来说,等同于私有,但可以派生类中可见。

#include <iostream>
using namespace std;
class Base
{
public:
int pub;
protected:
int pro;
private:
int pri;
};
class Drive:public Base
{
public:
void func()
{
pub = 10;
pro = 100;
// pri = 1000;
public;
int a;
protected:
int b;
private:
int c
};
//
int main()
{
Base b;
b.pub = 10;
// b.pro = 100;
// b.pri = 1000;
return 0;
}

派生类中的成员,包含两大部分,一类是从基类继承过来的,一类是自己增加的成员。从基类继承过过来的表现其共性,而新增的成员体现了其个性。

几点说明:
1,全盘接收,除了构造器与析构器。基类有可能会造成派生类的成员冗余,所以说基
类是需设计的。
2,派生类有了自己的个性,使派生类有了意义

派生类中由基类继承而来的成员的初始化工作还是由基类的构造函数完成,然后派生类
中新增的成员在派生类的构造函数中初始化。

派生类构造函数的语法:
派生类名::派生类名(参数总表):基类名(参数表),内嵌子对象(参数表)
{
派生类新增成员的初始化语句; //也可出现地参数列表中
}

构造函数的初始化顺序并不以上面的顺序进行,而是根据声明的顺序初始化。
如果基类中没有默认构造函数(无参),那么在派生类的构造函数中必须显示调用基类构
造函数,以初始化基类成员。

代码实现
祖父类
student.h
class Student
{
public:
Student(string sn,int n,char s);
~Student();
void dis();
private:
string name;
int num;
char sex;
};


student.cpp
Student::Student(string sn, int n, char s)
:name(sn),num(n),sex(s)
{
}
Student::~Student()
{
}
void Student:: dis()
{
cout<<name<<endl;
cout<<num<<endl;
cout<<sex<<endl;
}
父类
graduate.h
class Graduate:public Student
{
public:
Graduate(string sn,int in,char cs,float fs);
~Graduate();
void dump()
{
dis();
cout<<salary<<endl;
}
private:
float salary;
};

graduate.cpp
Graduate::Graduate(string sn, int in, char cs, float fs)
:Student(sn,in,cs),salary(fs)
{
}
Graduate::~Graduate()
{
}

 类成员
birthday.h
class Birthday
{
public:
Birthday(int y,int m,int d);
~Birthday();
void print();
private:
int year;
int month;
int day;
};

birthday.cpp
Birthday::Birthday(int y, int m, int d)
:year(y),month(m),day(d)
{
}
Birthday::~Birthday()
{
}
void Birthday::print()
{
cout<<year<<month<<day<<endl;
}

 子类
doctor.h
class Doctor:public Graduate
{
public:
Doctor(string sn,int in,char cs,float fs,string st,int iy,int im,in
t id);
~Doctor();
void disdump();
private:
string title; //调用的默认构造器,初始化为””
Birthday birth; //类中声明的类对象
};

doctor.cpp
Doctor::Doctor(string sn, int in, char cs, float fs, string st, int iy,
int im, int id)
:Graduate(sn,in,cs,fs),birth(iy,im,id),title(st)
{
}
Doctor::~Doctor()
{
}
void Doctor::disdump()
{
dump();
cout<<title<<endl;
birth.print();
}
测试代码
int main()
{
Student s("zhaosi",2001,'m');
s.dis();
cout<<"----------------"<<endl;
Graduate g("liuneng",2001,'x',2000);
g.dump();
cout<<"----------------"<<endl;
Doctor d("qiuxiang",2001,'y',3000,"doctor",2001,8,16);
d.disdump();
return 0;

c++ 内存空间和名称空间

  • 单独编译
  • 存储持续性、作用域和链接性
  • 定位和new运算符
  • 名称空间

  • 存储持续性
  • 定义命名空间:

    NameSpace 是对全局(Global scope)区域的再次划分

    命令空间的声明及 namespace 中可以包含的内容
    namespace NAMESPACE
    {
    全局变量 int a;
    数据类型 struct Stu{};
    函数 void func();
    其它命名空间 namespace
    }

    使用方法:

    直接指定 命名空间: Space::a = 5

    使用 using+命名空间+空间元素:using Space::a; a = 2000;
    使用 using +namespace+命名空间: using namespace Space;

    leetcodeday11 —盛最多水的容器

    本题用到的方法:双指针,在数组首尾部设两个指针,根据指针的值的大小,每次更新一个指针。

    给你 n 个非负整数 a1,a2,...,an每个数代表坐标中的一个点 (i, ai) 。在坐标内画 n 条垂直线,垂直线 i 的两个端点分别为 (i, ai) 和 (i, 0) 。找出其中的两条线,使得它们与 x 轴共同构成的容器可以容纳最多的水。

    说明:你不能倾斜容器。

    方法1:暴力求解,遍历就完了

    # @lc code=start
    class Solution:
        def maxArea(self, height: List[int]) -> int:
            maxwarter=0
            for i in range(len(height)-1):
                j=i+1
                while j<=len(height)-1:
                    new=min(height[i],height[j])*(j-i)
                    maxwarter=maxwarter if new<maxwarter else new
                    j=j+1
            return maxwarter
    # @lc code=end
    

    然而:超出时间限制了

    官方方法:双指针

    [1, 8, 6, 2, 5, 4, 8, 3, 7]

    在初始时,左右指针分别指向数组的左右两端,它们可以容纳的水量为 min(1, 7) * 8 = 8。

    此时我们需要移动一个指针。移动哪一个呢?直觉告诉我们,应该移动对应数字较小的那个指针(即此时的左指针)。这是因为,由于容纳的水量是由

    两个指针指向的数字中较小值 * 指针之间的距离

    决定的。如果我们移动数字较大的那个指针,那么前者「两个指针指向的数字中较小值」不会增加,后者「指针之间的距离」会减小,那么这个乘积会减小。因此,我们移动数字较大的那个指针是不合理的。因此,我们移动 数字较小的那个指针。

    有读者可能会产生疑问:我们可不可以同时移动两个指针? 先别急,我们先假设 总是移动数字较小的那个指针 的思路是正确的,在走完流程之后,我们再去进行证明。

    所以,我们将左指针向右移动:

    [1, 8, 6, 2, 5, 4, 8, 3, 7]

    此时可以容纳的水量为min(8,7)∗7=49。由于右指针对应的数字较小,我们移动右指针:

    [1, 8, 6, 2, 5, 4, 8, 3, 7]

    此时可以容纳的水量为 min(8,3)∗6=18。由于右指针对应的数字较小,我们移动右指针:

    [1, 8, 6, 2, 5, 4, 8, 3, 7]

    此时可以容纳的水量为min(8,8)∗5=40。两指针对应的数字相同,我们可以任意移动一个,例如左指针:

    [1, 8, 6, 2, 5, 4, 8, 3, 7]

    此时可以容纳的水量为min(6,8)∗4=24。由于左指针对应的数字较小,我们移动左指针,并且可以发现,在这之后左指针对应的数字总是较小,因此我们会一直移动左指针,直到两个指针重合。在这期间,对应的可以容纳的水量为:min(2,8)∗3=6,min(5,8)∗2=10,min(4,8)∗1=4。

    在我们移动指针的过程中,计算到的最多可以容纳的数量为 49,即为最终的答案。

    # @lc code=start
    class Solution:
        def maxArea(self, height: List[int]) -> int:
            maxwarter=0
            i=0
            j=len(height)-1
            while i<j:
                new =min(height[i],height[j])*(j-i)
                maxwarter=new if new>maxwarter else maxwarter
                if height[i]>=height[j]:
                   j=j-1
                else: i=i+1
    
            return maxwarter
    # @lc code=end
    晚安

    leetcodeday9 –回文数

    给你一个整数 x ,如果 x 是一个回文整数,返回 true ;否则,返回 false 。

    回文数是指正序(从左向右)和倒序(从右向左)读都是一样的整数。例如,121 是回文,而 123 不是。

    示例 1:

    输入:x = 121
    输出:true

    示例 2:

    输入:x = -121
    输出:false
    解释:从左向右读, 为 -121 。 从右向左读, 为 121- 。因此它不是一个回文数。

    示例 3:

    输入:x = 10
    输出:false
    解释:从右向左读, 为 01 。因此它不是一个回文数。

    首先我想的是字符串方法:只要判断首尾部的字符是否相同就可

    # @lc code=start
    class Solution:
        def isPalindrome(self, x: int) -> bool:
            s=str(x)
            length=len(s)
            i=0
            while i<=length-1:
                if s[i]==s[length-1]:
                    
                   i=i+1
                   length=length-1
                else:
                    return False
            return True
    
    # @lc code=end
    

    进阶:你能不将整数转为字符串来解决这个问题吗?

    第一想法是反转数字,判断两个数字是否一致:

    # @lc code=start
    class Solution:
        def isPalindrome(self, x: int) -> bool:
            y=x
            if x<0: 
                return False
            rev=0
            while x//10>0:
                rev=rev*10+x%10
                x=x//10
            rev=rev*10+x
            return rev==y

    但是,如果反转后的数字大于int.MAX,我们将遇到整数溢出问题。

    按照第二个想法,为了避免数字反转可能导致的溢出问题,为什么不考虑只反转 int 数字的一半?毕竟,如果该数字是回文,其后半部分反转后应该与原始数字的前半部分相同。

    例如,输入 1221,我们可以将数字 “1221” 的后半部分从 “21” 反转为 “12”,并将其与前半部分 “12” 进行比较,因为二者相同,我们得知数字 1221 是回文。

    leetcodeday8 –字符串转换整数 (atoi)

    请你来实现一个 myAtoi(string s) 函数,使其能将字符串转换成一个 32 位有符号整数(类似 C/C++ 中的 atoi 函数)。

    函数 myAtoi(string s) 的算法如下:

    • 读入字符串并丢弃无用的前导空格
    • 检查下一个字符(假设还未到字符末尾)为正还是负号,读取该字符(如果有)。 确定最终结果是负数还是正数。 如果两者都不存在,则假定结果为正。
    • 读入下一个字符,直到到达下一个非数字字符或到达输入的结尾。字符串的其余部分将被忽略。
    • 将前面步骤读入的这些数字转换为整数(即,”123″ -> 123, “0032” -> 32)。如果没有读入数字,则整数为 0 。必要时更改符号(从步骤 2 开始)。
    • 如果整数数超过 32 位有符号整数范围 [−231,  231 − 1] ,需要截断这个整数,使其保持在这个范围内。具体来说,小于 −231 的整数应该被固定为 −231 ,大于 231 − 1 的整数应该被固定为 231 − 1 。
    • 返回整数作为最终结果。

    注意:

    • 本题中的空白字符只包括空格字符 ' ' 。
    • 除前导空格或数字后的其余字符串外,请勿忽略 任何其他字符。

    示例 1:

    输入:s = "42"
    输出:42
    解释:加粗的字符串为已经读入的字符,插入符号是当前读取的字符。
    第 1 步:"42"(当前没有读入字符,因为没有前导空格)
             ^
    第 2 步:"42"(当前没有读入字符,因为这里不存在 '-' 或者 '+')
             ^
    第 3 步:"42"(读入 "42")
               ^
    解析得到整数 42 。
    由于 "42" 在范围 [-231, 231 - 1] 内,最终结果为 42 。

    示例 2:

    输入:s = "   -42"
    输出:-42
    解释:
    第 1 步:"-42"(读入前导空格,但忽视掉)
                ^
    第 2 步:"   -42"(读入 '-' 字符,所以结果应该是负数)
                 ^
    第 3 步:"   -42"(读入 "42")
                   ^
    解析得到整数 -42 。
    由于 "-42" 在范围 [-231, 231 - 1] 内,最终结果为 -42 。

    示例 3:

    输入:s = "4193 with words"
    输出:4193
    解释:
    第 1 步:"4193 with words"(当前没有读入字符,因为没有前导空格)
             ^
    第 2 步:"4193 with words"(当前没有读入字符,因为这里不存在 '-' 或者 '+')
             ^
    第 3 步:"4193 with words"(读入 "4193";由于下一个字符不是一个数字,所以读入停止)
                 ^
    解析得到整数 4193 。
    由于 "4193" 在范围 [-231, 231 - 1] 内,最终结果为 4193 。

    示例 4:

    输入:s = "words and 987"
    输出:0
    解释:
    第 1 步:"words and 987"(当前没有读入字符,因为没有前导空格)
             ^
    第 2 步:"words and 987"(当前没有读入字符,因为这里不存在 '-' 或者 '+')
             ^
    第 3 步:"words and 987"(由于当前字符 'w' 不是一个数字,所以读入停止)
             ^
    解析得到整数 0 ,因为没有读入任何数字。
    由于 0 在范围 [-231, 231 - 1] 内,最终结果为 0 。

    示例 5:

    输入:s = "-91283472332"
    输出:-2147483648
    解释:
    第 1 步:"-91283472332"(当前没有读入字符,因为没有前导空格)
             ^
    第 2 步:"-91283472332"(读入 '-' 字符,所以结果应该是负数)
              ^
    第 3 步:"-91283472332"(读入 "91283472332")
                         ^
    解析得到整数 -91283472332 。
    由于 -91283472332 小于范围 [-231, 231 - 1] 的下界,最终结果被截断为 -231 = -2147483648 。

    提示:

    • 0 <= s.length <= 200
    • s 由英文字母(大写和小写)、数字(0-9)、' ''+''-' 和 '.' 组成

    第一次尝试:根据题目要求,就硬写就完了,考虑各种情况:

    # @lc code=start
    class Solution:
        def myAtoi(self, s: str) -> int:
            s=s.lstrip()+" "
            j=0
            if s[0]=="-" and s[1] in  ["0","1","2","3","4","5","6","7","8","9"]: 
               for i in s[1:]:
                   re="-"
                   j=j+1
                   while i not in ["0","1","2","3","4","5","6","7","8","9"] or i==".":
                        return int(s[0:j]) if int(s[0:j])>-2**31 else -2**31
            elif s[0] =="+" and s[1] in  ["0","1","2","3","4","5","6","7","8","9"]:
                for i in s[1:]:
                   j=j+1
                   while i not in ["0","1","2","3","4","5","6","7","8","9"]or i==".":
                        return int(s[1:j])  if int(s[1:j])<2**31-1 else 2**31-1
            elif s[0] in  ["0","1","2","3","4","5","6","7","8","9"]:
                for i in s[1:]:
                   j=j+1
                   while i not in ["0","1","2","3","4","5","6","7","8","9"]or i==".":
                        return int(s[0:j])  if int(s[0:j])<2**31-1 else 2**31-1
            else:return 0 
                
    # @lc code=end
    

    leetcodeday7 –整数反转

    给你一个 32 位的有符号整数 x ,返回将 x 中的数字部分反转后的结果。

    如果反转后整数超过 32 位的有符号整数的范围 [−231,  231 − 1] ,就返回 0。

    假设环境不允许存储 64 位整数(有符号或无符号)。

    示例 1:

    输入:x = 123
    输出:321
    示例 2:

    输入:x = -123
    输出:-321
    示例 3:

    输入:x = 120
    输出:21
    示例 4:

    输入:x = 0
    输出:0
     

    提示:

    -231 <= x <= 231 – 1

    来源:力扣(LeetCode)
    链接:https://leetcode-cn.com/problems/reverse-integer
    著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。

    解题:这里首先想到的是先转字符串,然后反转字符串,但其实这种方法不能满足系统32位的限制。

    因此参考官方解法,是一种纯数学方法,代码比较简单,但数学推导复杂:

    记 rev 为翻转后的数字,为完成翻转,我们可以重复「弹出」x 的末尾数字,将其「推入」rev 的末尾,直至 x 为 0。

    要在没有辅助栈或数组的帮助下「弹出」和「推入」数字,我们可以使用如下数学方法:

    // 弹出 x 的末尾数字 digit
    digit = x % 10
    x /= 10

    // 将数字 digit 推入 rev 末尾
    rev = rev * 10 + digit

    题目需要判断反转后的数字是否超过 3232 位有符号整数的范围 \([-2^{31},2^{31}-1]\),例如 x=2123456789x=2123456789 反转后的 \(\textit{rev}=9876543212>2^{31}-1=2147483647\),超过了 32 位有符号整数的范围。

    因此我们需要在「推入」数字之前,判断是否满足

    −231≤rev⋅10+digit≤231−1

    若该不等式不成立则返回 0。

    但是题目要求不允许使用 6464 位整数,即运算过程中的数字必须在 3232 位有符号整数的范围内,因此我们不能直接按照上述式子计算,需要另寻他路。

    我们需要在「推入」数字之前,判断是否满足 :

    $$
    \left\lceil\frac{-2^{31}}{10}\right\rceil \leq \operatorname{rev} \leq\left\lfloor\frac{2^{31}-1}{10}\right\rfloor
    $$

    是否成立,若不成立则返回 0

    # @lc code=start
    class Solution:
        def reverse(self, x: int) -> int:
            INT_MIN, INT_MAX = -2**31, 2**31 - 1
    
            rev = 0
            while x != 0:
                # INT_MIN 也是一个负数,不能写成 rev < INT_MIN // 10
                if rev < INT_MIN // 10 + 1 or rev > INT_MAX // 10:
                    return 0
                digit = x % 10
                # Python3 的取模运算在 x 为负数时也会返回 [0, 9) 以内的结果,因此这里需要进行特殊判断
                if x < 0 and digit > 0:
                    digit -= 10
    
                # 同理,Python3 的整数除法在 x 为负数时会向下(更小的负数)取整,因此不能写成 x //= 10
                x = (x - digit) // 10
                rev = rev * 10 + digit
            
            return rev
    
            # @lc code=end