类的定义
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++继承权限和继承方式