所以,在罗伯特·莱弗尔的“面向对象的C++编程,第4版”一书中,问题9-2的解决方案似乎存在一些问题。所以问题是,如果我想创建一个带有像Pstring = "This is a string"这样的语句的Pstring对象,那么Pstring构造函数将只调用String类中没有参数的构造函数,而不是使用一个char[]参数的第二个构造函数。有谁知道是什么原因造成了这种问题,并解决了这个问题?谢谢!
#include <iostream>
#include <cstring>
using namespace std;
////////////////////////////////////////////////////////////////
class String //base class
{
protected: //Note: can't be private
enum {
SZ = 80
}; //size of all String objects
char str[SZ]; //holds a C-string
public:
String() //constructor 0, no args
{
str[0] = '\0';
}
String(char s[]) //constructor 1, one arg
{
strcpy(str, s);
} // convert string to String
void display() const //display the String
{
cout << str;
}
operator char*() //conversion function
{
return str;
} //convert String to C-string
};
////////////////////////////////////////////////////////////////
class Pstring: public String //derived class
{
public:
Pstring(char s[]); //constructor
};
//--------------------------------------------------------------
Pstring::Pstring(char s[]) //constructor for Pstring
{
if (strlen(s) > SZ - 1) //if too long,
{
for (int j = 0; j < SZ - 1; j++) { //copy the first SZ-1
str[j] = s[j]; //characters "by hand"
str[j] = '\0';
} //add the null character
} else
//not too long,
String(s); //so construct normally
}
////////////////////////////////////////////////////////////////
int main() { //define String
String s1 = "This is a string"; // This works great
s1.display();
Pstring s2 = "This is a string"; // *** Here, nothing will be assigned to s2****
s2.display(); // *** Nothing will be printed here***
return 0;
}发布于 2020-05-30 20:38:53
在函数参数中,T[] (在您的例子中,T是char )实际上是一个T*。
在C++中,字符串文本是一个const char[N]固定数组,它衰变为指向第一个元素的const char*指针。但是,没有任何构造函数接受这些类型中的任何一个作为参数。const char*不能给char*。需要将const添加到构造函数中:
String(const char s[])
Pstring(const char s[])
此外,在String(s)构造函数的主体中调用Pstring并不像您期望的那样使用基类String构造函数初始化Pstring对象。相反,它构建了一个临时的String对象,该对象立即超出作用域。Pstring对象不受此影响。
派生构造函数可以调用基类构造函数的唯一位置是在中。在您的示例中,没有这样的调用,因此编译器在进入派生构造函数的主体之前隐式调用基类默认(0-param)构造函数。这无助于您,因为您希望基类使用数据初始化str缓冲区。
可以这样做的一种方法是向String中添加另一个构造函数,该构造函数以用户定义的长度作为输入,然后从Pstring构造函数调用该构造函数,例如:
String(const char s[], size_t len)
{
len = std::min(len, SZ-1);
memcpy(str, s, len);
str[len] = '\0';
}
Pstring::Pstring(const char s[])
: String(s, strlen(s))
{
}注意,您的1-param String构造函数有一个缓冲区溢出等待发生,因为用户可以直接构造一个输入大于SZ字符长度的String对象。String构造函数应该使用strncpy()而不是strcpy()
String(const char s[])
{
strncpy(str, s, SZ);
str[SZ-1] = '\0'; // in case s is >= SZ chars
}这就使得1-param Pstring构造函数变得多余--特别是因为它一开始就没有正确地处理空终止符,因为终止符的分配需要在for循环之外,例如:
Pstring::Pstring(const char s[])
{
if (strlen(s) >= SZ)
{
for (int j = 0; j < SZ - 1; j++) {
str[j] = s[j];
}
// alternatively: memcpy(str, sz, SZ-1);
str[SZ-1] = '\0'; // <-- moved here
}
else
strcpy(str, s);
}发布于 2020-05-30 20:48:35
在此转换构造函数中
Pstring::Pstring(char s[]) //constructor for Pstring
{
if (strlen(s) > SZ - 1) //if too long,
{
for (int j = 0; j < SZ - 1; j++) { //copy the first SZ-1
str[j] = s[j]; //characters "by hand"
str[j] = '\0';
} //add the null character
} else
//not too long,
String(s); //so construct normally
}首先调用类String的默认构造函数,然后将控件传递给类Pstring的构造函数。
因此,数据成员设置如下
String() //constructor 0, no args
{
str[0] = '\0';
}作为参数,即字符串文本"This is a string" (顺便说一句,由于数组向指针的隐式转换而具有const char *类型),它的长度小于SZ,那么在构造函数体Pstring中,对数据成员str什么也不做。这句话
String(s);创建一个String类型的临时对象,该对象立即被删除。
你需要的至少是写
strcpy( str, s );而不是创建临时对象。
注意具有参数的构造函数应声明如下
String( const char s[] );和
Pstring( const char s[]);如果要使用字符串文本作为构造函数的参数。
你可以移动这个代码片段
if (strlen(s) > SZ - 1) //if too long,
{
for (int j = 0; j < SZ - 1; j++) { //copy the first SZ-1
str[j] = s[j]; //characters "by hand"
str[j] = '\0';
} //add the null character
} else
//not too long,
String(s); //so construct normally使用参数将构造函数Pstring转换为构造函数String,并将其替换为strncpy的一个调用,如
strncpy( str, s, SZ - 1 );
str[SZ-1] = '\0';发布于 2020-05-30 21:01:06
在C++,constructors aren't allowed to be called like this中
else
//not too long,
String(s); C++希望您使用它的初始化列表(有关一些示例,请参见the link above )。
如果要从子构造函数内部调用父类中的一部分构造,则可以使用受保护的方法:
class String //base class
{
protected:
void commonTask(char s[]) {
// do something...
}
public:
String(char s[])
{
commonTask(s);
}
};
class Pstring: public String
{
public:
Pstring(char s[]) { //constructor
if(someCondition) {
commonTask(s);
}
}
};我这里使用的是伪代码,但希望你能理解。
https://stackoverflow.com/questions/62108317
复制相似问题