类的定义

类的定义

6. 类定义的语法格式

  • 在定义数据成员时不能直接进行初始化,要为数据成员提供初始值应该放在构造函数中。
  • 类定义的末尾应添加分号。

7. C++ 中类成员访问权限有哪几种,简述其作用?

  • private:类中的 private 成员只能够在本类中或者友元类中进行访问。子
    类或者外界是无法访问私有成员的。
  • protected:类中的 protected 成员只允许本类或者子类中进行访问。外界
    无法访问 protected 成员。在定义类时,如果希望该成员能够被子类继承,但是不被外界访问,可以定义 protected 成员。
  • public:类中的 public 成员能够在本类、子类和外界中都能够进行访问。
    通常,类中向用户提供的服务设计为 public 成员。

8. 如何在类中定义常量成员并为其初始化?

要为常量初始化,需要在类的构造函数的初始化部分进行,也就是在构
造函数的函数体前使用 “:” 定义初始化区域,在该区域进行初始化。

class CBook
{
public:
    const double m_Price; //定义常量成员
    CBook() :m_Price(89.8) //为常量进行初始化
    {
    }
};

9. 由析构函数引起的递归调用

析构函数由系统自动调用。有两种情况将导致析构函数被调用。一是对
象的作用域消失,二是使用 delete 运算符释放对象。

class CNode
{
public:
    CNode* pNext;
    CNode() //构造函数
    {
        pNext = this;
    }
    ~CNode() //析构函数
    {
        if(pNext!=NULL)
        {
            delete pNext;
            pNext = NULL;
        }
    }
};

上面代码出现了递归调用。在析构函数中执行 “delete pNext;” 语句时导致递归。因为在析构函数中使用 delete 运算符释放自身,这将导致再次调用析构函数,致使析构函数出现递归。

10. 在 C++ 中如何定义内联成员函数

  • 在定义成员函数时使用inline 关键字。
class CBook
{
private:
      double m_Price;
public:
      inline void SetPrice(double Price); //使用 inline 关键字定义内联函数
      CBook()
      {
      }
};
void CBook::SetPrice(double Price)
{
      m_Price = Price;
}
  • 在定义成员函数时直接写出函数体。
class CBook
{
private:
      double m_Price;
public:
      void SetPrice(double Price) //在定义成员函数时直接给出函数体,自动为内联函数
      {
           m_Price = Price;
      }
      CBook()
      {
      }
};

11. 构造函数与普通函数在形式上有何不同?

  • 名字与类相同,无返回值
  • 无参数,或若干参数,无参数的构造函数叫默认构造函数;如果不提供构造函数,则编译器提供默认构造函数,如提供了任何形式的构造函数,编译器不会提供默认构造函数

12. 如何定义两个类互为成员的情况?

classA
{
private:
    B m_B;
};
class B
{
private:
    Am_A;
};

不用进行编译,就可以预知存在错误。因为在类 A 之前,没有发现类 B 的定义,直接使用了类 B。为了解决这个矛盾,需要在类 A 上方前导声明类 B。但是这还不能完全解决问题。因为前导声明只是声明一个类,而没有类的定义,编译器在编译类 A 时需要实例化类 B,但是却没有发现类 B 的定义,而只是发现了类 B 的声明。解决方式是在类 A 中,将 m_B 对象修改为指针类型。

class B; //前导声明类 B
classA
{
private:
    B *m_B; //定义类 B 的指针类型
};
class B
{
private:
    Am_A;
};

13. 已知 String 类的定义, 请添加实现部分。

class String
{
public:
    String(const char *str = NULL); //通用构造函数
    String(const String &another); //拷贝构造函数
    ~ String(); //析构函数
    String &operator =(const String &rhs); //赋值函数
private:
    char *m_data; //用于保存字符串
};

在定义一个类时如果没有指定这些函数,编译器会为其提供这 4 个特殊的函数。除了构造函数之外,其余 3 个函数都具有特定的函数原型。例如,析构函数的名称为 “~” 加上类名,没有参数和返回值。拷贝构造函数与类名相同,参数为一个常量引用类型参数。赋值函数参数为常量引用类型,返回值为类引用类型。

构造函数用于创建类对象。析构函数用于释放对象。拷贝构造函数用于
在类对象作为函数参数或函数返回值时被调用,用于临时构建对象。赋值函数用于实现对象间的直接赋值。

参考代码如下:

String::String(const char *str) //实现构造函数
{
    if ( str == NULL ) //判断参数是否为空
    {
        m_data = new char[1] ;
        m_data[0] = '\0' ;
    }
    else
    {
        m_data = new char[strlen(str) + 1];
        strcpy(m_data, str);
    }
}
String::String(const String &another) //实现拷贝构造函数
{
    m_data = new char[strlen(another.m_data) + 1];
    strcpy(m_data, another.m_data);
}
String& String::operator =(const String &rhs) //实现赋值函数
{
    if ( this == &rhs)
        return *this ;
    delete []m_data; //删除原来的数据,新开一块内存
    m_data = new char[strlen(rhs.m_data) + 1];
    strcpy(m_data,rhs.m_data);
    return *this ;
}
String::~String() //实现析构函数
{
    delete []m_data ;
}

14. 在定义类的成员函数时使用 mutable 关键字的作用是什么?

在定义类的方法时,如果在方法的末尾使用 const 关键字,表示该方法为 const 方法,此时在方法中不允许修改对象的信息。例如,下面的代码将出现编译错误。

class CStudent
{
private:
    intAge;
    int Weight;
public:
    void SetAge(intAge);
    int GetAge()const; //定义 const 方法
};
void CStudent::SetAge(intAge)
{
    this->Age =Age; //通过 this 指针来访问成员 Age
}
int CStudent::GetAge()const
{
    Weight = 10; //此处将出现编译错误
    returnAge;
}

上述代码在 const 方法中修改 Weight 成员导致的语法错误。为了能够在 const 方法中修改对象的成员信息,可以在成员前使用 mutable 关键字。例如,下面的代码是完全合法的。

class CStudent
{
private:
    intAge;
    mutable int Weight;
public:
    void SetAge(intAge);
    int GetAge() const ;
};
void CStudent::SetAge(intAge)
{
    this->Age =Age; //通过 this 指针来访问成员 Age
}
int CStudent::GetAge() const //实现 const 方法
{
    Weight = 10; //在 const 方法中为数据成员赋值
    return Age;
}

当需要在 const 方法中修改对象的数据成员时,可以在数据成员前使用 mutable 关键字,防止出现编译错误。

参考资料:
C++继承权限和继承方式

你可能感兴趣的:(类的定义)